Skip to content

Commit e45d869

Browse files
committed
expand: Make #[derive(A, B, ...)] cfg-eval its input only for A, B, ...
1 parent 3740ba2 commit e45d869

File tree

6 files changed

+95
-51
lines changed

6 files changed

+95
-51
lines changed

compiler/rustc_builtin_macros/src/cfg_eval.rs

+11-13
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@ use crate::util::check_builtin_macro_attribute;
22

33
use rustc_ast as ast;
44
use rustc_ast::mut_visit::MutVisitor;
5+
use rustc_ast::ptr::P;
56
use rustc_ast::tokenstream::CanSynthesizeMissingTokens;
67
use rustc_ast::visit::Visitor;
78
use rustc_ast::{mut_visit, visit};
89
use rustc_ast::{AstLike, Attribute};
910
use rustc_expand::base::{Annotatable, ExtCtxt};
1011
use rustc_expand::config::StripUnconfigured;
1112
use rustc_expand::configure;
13+
use rustc_feature::Features;
1214
use rustc_parse::parser::ForceCollect;
1315
use rustc_session::utils::FlattenNonterminals;
14-
15-
use rustc_ast::ptr::P;
16+
use rustc_session::Session;
1617
use rustc_span::symbol::sym;
1718
use rustc_span::Span;
1819
use smallvec::SmallVec;
@@ -24,19 +25,16 @@ crate fn expand(
2425
annotatable: Annotatable,
2526
) -> Vec<Annotatable> {
2627
check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval);
27-
cfg_eval(ecx, annotatable)
28+
vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable)]
2829
}
2930

30-
crate fn cfg_eval(ecx: &ExtCtxt<'_>, annotatable: Annotatable) -> Vec<Annotatable> {
31-
let mut visitor = CfgEval {
32-
cfg: &mut StripUnconfigured {
33-
sess: ecx.sess,
34-
features: ecx.ecfg.features,
35-
config_tokens: true,
36-
},
37-
};
38-
let annotatable = visitor.configure_annotatable(annotatable);
39-
vec![annotatable]
31+
crate fn cfg_eval(
32+
sess: &Session,
33+
features: Option<&Features>,
34+
annotatable: Annotatable,
35+
) -> Annotatable {
36+
CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true } }
37+
.configure_annotatable(annotatable)
4038
}
4139

4240
struct CfgEval<'a, 'b> {

compiler/rustc_builtin_macros/src/derive.rs

+34-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use crate::cfg_eval::cfg_eval;
22

3-
use rustc_ast::{self as ast, attr, token, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
3+
use rustc_ast as ast;
4+
use rustc_ast::{attr, token, GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
45
use rustc_errors::{struct_span_err, Applicability};
56
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
67
use rustc_feature::AttributeTemplate;
78
use rustc_parse::validate_attr;
89
use rustc_session::Session;
9-
use rustc_span::symbol::sym;
10+
use rustc_span::symbol::{sym, Ident};
1011
use rustc_span::Span;
1112

1213
crate struct Expander;
@@ -26,6 +27,7 @@ impl MultiItemModifier for Expander {
2627
return ExpandResult::Ready(vec![item]);
2728
}
2829

30+
let (sess, features) = (ecx.sess, ecx.ecfg.features);
2931
let result =
3032
ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| {
3133
let template =
@@ -38,7 +40,8 @@ impl MultiItemModifier for Expander {
3840
template,
3941
);
4042

41-
attr.meta_item_list()
43+
let mut resolutions: Vec<_> = attr
44+
.meta_item_list()
4245
.unwrap_or_default()
4346
.into_iter()
4447
.filter_map(|nested_meta| match nested_meta {
@@ -54,17 +57,42 @@ impl MultiItemModifier for Expander {
5457
report_path_args(sess, &meta);
5558
meta.path
5659
})
57-
.map(|path| (path, None))
58-
.collect()
60+
.map(|path| (path, dummy_annotatable(), None))
61+
.collect();
62+
63+
// Do not configure or clone items unless necessary.
64+
match &mut resolutions[..] {
65+
[] => {}
66+
[(_, first_item, _), others @ ..] => {
67+
*first_item = cfg_eval(sess, features, item.clone());
68+
for (_, item, _) in others {
69+
*item = first_item.clone();
70+
}
71+
}
72+
}
73+
74+
resolutions
5975
});
6076

6177
match result {
62-
Ok(()) => ExpandResult::Ready(cfg_eval(ecx, item)),
78+
Ok(()) => ExpandResult::Ready(vec![item]),
6379
Err(Indeterminate) => ExpandResult::Retry(item),
6480
}
6581
}
6682
}
6783

84+
// The cheapest `Annotatable` to construct.
85+
fn dummy_annotatable() -> Annotatable {
86+
Annotatable::GenericParam(ast::GenericParam {
87+
id: ast::DUMMY_NODE_ID,
88+
ident: Ident::invalid(),
89+
attrs: Default::default(),
90+
bounds: Default::default(),
91+
is_placeholder: false,
92+
kind: GenericParamKind::Lifetime,
93+
})
94+
}
95+
6896
fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
6997
let item_kind = match item {
7098
Annotatable::Item(item) => Some(&item.kind),

compiler/rustc_expand/src/base.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,7 @@ impl SyntaxExtension {
835835
/// Error type that denotes indeterminacy.
836836
pub struct Indeterminate;
837837

838-
pub type DeriveResolutions = Vec<(ast::Path, Option<Lrc<SyntaxExtension>>)>;
838+
pub type DeriveResolutions = Vec<(ast::Path, Annotatable, Option<Lrc<SyntaxExtension>>)>;
839839

840840
pub trait ResolverExpand {
841841
fn next_node_id(&mut self) -> NodeId;

compiler/rustc_expand/src/expand.rs

+2-28
Original file line numberDiff line numberDiff line change
@@ -500,42 +500,16 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
500500
.resolver
501501
.take_derive_resolutions(expn_id)
502502
.map(|derives| {
503-
enum AnnotatableRef<'a> {
504-
Item(&'a P<ast::Item>),
505-
Stmt(&'a ast::Stmt),
506-
}
507-
let item = match &fragment {
508-
AstFragment::Items(items) => match &items[..] {
509-
[item] => AnnotatableRef::Item(item),
510-
_ => unreachable!(),
511-
},
512-
AstFragment::Stmts(stmts) => match &stmts[..] {
513-
[stmt] => AnnotatableRef::Stmt(stmt),
514-
_ => unreachable!(),
515-
},
516-
_ => unreachable!(),
517-
};
518-
519503
derive_invocations.reserve(derives.len());
520504
derives
521505
.into_iter()
522-
.map(|(path, _exts)| {
506+
.map(|(path, item, _exts)| {
523507
// FIXME: Consider using the derive resolutions (`_exts`)
524508
// instead of enqueuing the derives to be resolved again later.
525509
let expn_id = ExpnId::fresh(None);
526510
derive_invocations.push((
527511
Invocation {
528-
kind: InvocationKind::Derive {
529-
path,
530-
item: match item {
531-
AnnotatableRef::Item(item) => {
532-
Annotatable::Item(item.clone())
533-
}
534-
AnnotatableRef::Stmt(stmt) => {
535-
Annotatable::Stmt(P(stmt.clone()))
536-
}
537-
},
538-
},
512+
kind: InvocationKind::Derive { path, item },
539513
fragment_kind,
540514
expansion_data: ExpansionData {
541515
id: expn_id,

compiler/rustc_resolve/src/macros.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
380380
has_derive_copy: false,
381381
});
382382
let parent_scope = self.invocation_parent_scopes[&expn_id];
383-
for (i, (path, opt_ext)) in entry.resolutions.iter_mut().enumerate() {
383+
for (i, (path, _, opt_ext)) in entry.resolutions.iter_mut().enumerate() {
384384
if opt_ext.is_none() {
385385
*opt_ext = Some(
386386
match self.resolve_macro_path(

src/test/ui/proc-macro/attribute-after-derive.stdout

+46-2
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
130130
span: $DIR/attribute-after-derive.rs:25:24: 28:2 (#0),
131131
},
132132
]
133-
PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { }
133+
PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { #[cfg(FALSE)] field : u8, }
134134
PRINT-ATTR INPUT (DEBUG): TokenStream [
135135
Ident {
136136
ident: "struct",
@@ -142,7 +142,51 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
142142
},
143143
Group {
144144
delimiter: Brace,
145-
stream: TokenStream [],
145+
stream: TokenStream [
146+
Punct {
147+
ch: '#',
148+
spacing: Alone,
149+
span: $DIR/attribute-after-derive.rs:26:5: 26:6 (#0),
150+
},
151+
Group {
152+
delimiter: Bracket,
153+
stream: TokenStream [
154+
Ident {
155+
ident: "cfg",
156+
span: $DIR/attribute-after-derive.rs:26:7: 26:10 (#0),
157+
},
158+
Group {
159+
delimiter: Parenthesis,
160+
stream: TokenStream [
161+
Ident {
162+
ident: "FALSE",
163+
span: $DIR/attribute-after-derive.rs:26:11: 26:16 (#0),
164+
},
165+
],
166+
span: $DIR/attribute-after-derive.rs:26:10: 26:17 (#0),
167+
},
168+
],
169+
span: $DIR/attribute-after-derive.rs:26:6: 26:18 (#0),
170+
},
171+
Ident {
172+
ident: "field",
173+
span: $DIR/attribute-after-derive.rs:27:5: 27:10 (#0),
174+
},
175+
Punct {
176+
ch: ':',
177+
spacing: Alone,
178+
span: $DIR/attribute-after-derive.rs:27:10: 27:11 (#0),
179+
},
180+
Ident {
181+
ident: "u8",
182+
span: $DIR/attribute-after-derive.rs:27:12: 27:14 (#0),
183+
},
184+
Punct {
185+
ch: ',',
186+
spacing: Alone,
187+
span: $DIR/attribute-after-derive.rs:27:14: 27:15 (#0),
188+
},
189+
],
146190
span: $DIR/attribute-after-derive.rs:25:24: 28:2 (#0),
147191
},
148192
]

0 commit comments

Comments
 (0)