Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3983,6 +3983,7 @@ dependencies = [
name = "rustc_expand"
version = "0.0.0"
dependencies = [
"bitflags",
"rustc_ast",
"rustc_ast_passes",
"rustc_ast_pretty",
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_builtin_macros/src/deriving/clone.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, Safety, VariantData};
use rustc_data_structures::fx::FxHashSet;
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_expand::base::{Annotatable, ExtCtxt, SpecialDerives};
use rustc_span::{DUMMY_SP, Ident, Span, kw, sym};
use thin_vec::{ThinVec, thin_vec};

Expand Down Expand Up @@ -37,7 +37,7 @@ pub(crate) fn expand_deriving_clone(
ItemKind::Struct(_, Generics { params, .. }, _)
| ItemKind::Enum(_, Generics { params, .. }, _) => {
let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
let has_derive_copy = cx.resolver.has_derive_copy(container_id);
let has_derive_copy = cx.resolver.has_derives(container_id, SpecialDerives::COPY);
if has_derive_copy
&& !params
.iter()
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind, Safety, ast};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_expand::base::{Annotatable, ExtCtxt, SpecialDerives};
use rustc_span::{Ident, Span, sym};
use thin_vec::{ThinVec, thin_vec};

Expand Down Expand Up @@ -43,7 +43,7 @@ pub(crate) fn expand_deriving_partial_ord(
};

let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
let has_derive_ord = cx.resolver.has_derive_ord(container_id);
let has_derive_ord = cx.resolver.has_derives(container_id, SpecialDerives::ORD);
let is_simple_candidate = |params: &ThinVec<ast::GenericParam>| -> bool {
has_derive_ord
&& !params.iter().any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_expand/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ doctest = false

[dependencies]
# tidy-alphabetical-start
bitflags = "2.9.1"
rustc_ast = { path = "../rustc_ast" }
rustc_ast_passes = { path = "../rustc_ast_passes" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
Expand Down
17 changes: 13 additions & 4 deletions compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1115,10 +1115,8 @@ pub trait ResolverExpand {
fn check_unused_macros(&mut self);

// Resolver interfaces for specific built-in macros.
/// Does `#[derive(...)]` attribute with the given `ExpnId` have built-in `Copy` inside it?
fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool;
/// Does `#[derive(...)]` attribute with the given `ExpnId` have built-in `Ord` inside it?
fn has_derive_ord(&self, expn_id: LocalExpnId) -> bool;
/// Does `#[derive(...)]` attribute with the given `ExpnId` have the given special built-in derives inside it?
fn has_derives(&self, expn_id: LocalExpnId, derives: SpecialDerives) -> bool;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be called has_special_derives() seeing it's only related to the specific subset denoted by SpecialDerives?

/// Resolve paths inside the `#[derive(...)]` attribute with the given `ExpnId`.
fn resolve_derives(
&mut self,
Expand Down Expand Up @@ -1389,6 +1387,17 @@ impl<'a> ExtCtxt<'a> {
}
}

bitflags::bitflags! {
/// Set of special built-in derives that can affect expansion of other derives.
/// E.g., deriving `Copy` affects how `Clone` is derived,
/// and deriving `Ord` affects how `PartialOrd` is derived.
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct SpecialDerives: u8 {
const COPY = 1 << 0;
const ORD = 1 << 1;
}
}

/// Resolves a `path` mentioned inside Rust code, returning an absolute path.
///
/// This unifies the logic used for resolving `include_X!`.
Expand Down
12 changes: 4 additions & 8 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{FreezeReadGuard, FreezeWriteGuard};
use rustc_data_structures::unord::{UnordItems, UnordMap, UnordSet};
use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed, LintBuffer};
use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind};
use rustc_expand::base::{DeriveResolution, SpecialDerives, SyntaxExtension, SyntaxExtensionKind};
use rustc_feature::BUILTIN_ATTRIBUTES;
use rustc_hir::attrs::StrippedCfgItem;
use rustc_hir::def::Namespace::{self, *};
Expand Down Expand Up @@ -1311,10 +1311,7 @@ impl ExternPreludeEntry<'_> {
struct DeriveData {
resolutions: Vec<DeriveResolution>,
helper_attrs: Vec<(usize, IdentKey, Span)>,
// if this list keeps getting extended, we could use `bitflags`,
// something like what [`rustc_type_ir::flags::TypeFlags`] is doing.
has_derive_copy: bool,
has_derive_ord: bool,
has_derives: SpecialDerives,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be called has_special_derives? It doesn't relate to derives broadly, just a specific few? Or perhaps even special_derives?

}

pub struct ResolverOutputs<'tcx> {
Expand Down Expand Up @@ -1450,11 +1447,10 @@ pub struct Resolver<'ra, 'tcx> {
multi_segment_macro_resolutions:
CmRefCell<Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, Namespace)>>,
builtin_attrs: Vec<(Ident, ParentScope<'ra>)> = Vec::new(),
/// `derive(Copy)` marks items they are applied to so they are treated specially later.
/// Some built-in derives marks items they are applied to so they are treated specially later.
/// Derive macros cannot modify the item themselves and have to store the markers in the global
/// context, so they attach the markers to derive container IDs using this resolver table.
containers_deriving_copy: FxHashSet<LocalExpnId> = default::fx_hash_set(),
containers_deriving_ord: FxHashSet<LocalExpnId> = default::fx_hash_set(),
containers_special_derives: FxHashMap<LocalExpnId, SpecialDerives> = default::fx_hash_map(),
/// Parent scopes in which the macros were invoked.
/// FIXME: `derives` are missing in these parent scopes and need to be taken from elsewhere.
invocation_parent_scopes: FxHashMap<LocalExpnId, ParentScope<'ra>> = default::fx_hash_map(),
Expand Down
45 changes: 22 additions & 23 deletions compiler/rustc_resolve/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rustc_ast_pretty::pprust;
use rustc_attr_parsing::AttributeParser;
use rustc_errors::{Applicability, DiagCtxtHandle, StashKey};
use rustc_expand::base::{
Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension,
Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SpecialDerives, SyntaxExtension,
SyntaxExtensionKind,
};
use rustc_expand::compile_declarative_macro;
Expand Down Expand Up @@ -375,12 +375,8 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
}
}

fn has_derive_copy(&self, expn_id: LocalExpnId) -> bool {
self.containers_deriving_copy.contains(&expn_id)
}

fn has_derive_ord(&self, expn_id: LocalExpnId) -> bool {
self.containers_deriving_ord.contains(&expn_id)
fn has_derives(&self, expn_id: LocalExpnId, derives: SpecialDerives) -> bool {
self.containers_special_derives.get(&expn_id).map_or(false, |d| d.contains(derives))
}

fn resolve_derives(
Expand All @@ -401,8 +397,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
let entry = derive_data.entry(expn_id).or_insert_with(|| DeriveData {
resolutions: derive_paths(),
helper_attrs: Vec::new(),
has_derive_copy: false,
has_derive_ord: false,
has_derives: SpecialDerives::empty(),
});
let parent_scope = self.invocation_parent_scopes[&expn_id];
for (i, resolution) in entry.resolutions.iter_mut().enumerate() {
Expand All @@ -424,8 +419,12 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
.map(|&name| (i, IdentKey { name, ctxt }, span)),
);
}
entry.has_derive_copy |= ext.builtin_name == Some(sym::Copy);
entry.has_derive_ord |= ext.builtin_name == Some(sym::Ord);
if ext.builtin_name == Some(sym::Copy) {
entry.has_derives |= SpecialDerives::COPY
}
if ext.builtin_name == Some(sym::Ord) {
entry.has_derives |= SpecialDerives::ORD
}
ext
}
Ok(_) | Err(Determinacy::Determined) => self.dummy_ext(MacroKind::Derive),
Expand All @@ -450,22 +449,22 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
})
.collect();
self.helper_attrs.insert(expn_id, helper_attrs);
// Mark this derive as having `Copy` either if it has `Copy` itself or if its parent derive
// has `Copy`, to support `#[derive(Copy, Clone)]`, `#[derive(Clone, Copy)]`, or
// `#[derive(Copy)] #[derive(Clone)]`. We do this because the code generated for
// `derive(Clone)` changes if `derive(Copy)` is also present.
// Mark this derive container as having special built-in derives either if it
// has them itself or if its parent derive container has them, to support
// e.g. `#[derive(Copy, Clone)]`, `#[derive(Clone, Copy)]`, or
// `#[derive(Copy)] #[derive(Clone)]`. This is needed because the code
// generated for certain derives (e.g. `Clone`, `PartialOrd`) changes if
// other derives (e.g. `Copy`, `Ord`) are also present.
//
// FIXME(#124794): unfortunately this doesn't work with `#[derive(Clone)] #[derive(Copy)]`.
// When the `Clone` impl is generated the `#[derive(Copy)]` hasn't been processed and
// `has_derive_copy` hasn't been set yet.
if entry.has_derive_copy || self.has_derive_copy(parent_scope.expansion) {
self.containers_deriving_copy.insert(expn_id);
// the derive markers haven't been set yet.
let mut all_derives = entry.has_derives;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all_special_derives? Again, it's just a specific subset of built-in traits.

if let Some(parent_derives) = self.containers_special_derives.get(&parent_scope.expansion) {
all_derives |= *parent_derives;
}
// Similar to the above `Copy` and `Clone` case, the code generated for
// `derive(PartialOrd)` changes if `derive(Ord)` is also present.
// FIXME(makai410): this also doesn't work with `#[derive(PartialOrd)] #[derive(Ord)]`.
if entry.has_derive_ord || self.has_derive_ord(parent_scope.expansion) {
self.containers_deriving_ord.insert(expn_id);
if !all_derives.is_empty() {
self.containers_special_derives.insert(expn_id, all_derives);
}
assert!(self.derive_data.is_empty());
self.derive_data = derive_data;
Expand Down
Loading