Auto merge of #87220 - petrochenkov:derivecfglimit2, r=Aaron1011
Make `#[derive(A, B, ...)]` cfg-eval its input only for `A, B, ...` and stabilize `feature(macro_attributes_in_derive_output)` Stabilization report: https://github.com/rust-lang/rust/pull/87220#issuecomment-881923657 Closes #81119 r? `@Aaron1011`
This commit is contained in:
commit
60fe8b3a65
9 changed files with 124 additions and 157 deletions
|
@ -2,6 +2,7 @@ use crate::util::check_builtin_macro_attribute;
|
|||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::mut_visit::MutVisitor;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::tokenstream::CanSynthesizeMissingTokens;
|
||||
use rustc_ast::visit::Visitor;
|
||||
use rustc_ast::{mut_visit, visit};
|
||||
|
@ -9,10 +10,10 @@ use rustc_ast::{AstLike, Attribute};
|
|||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_expand::config::StripUnconfigured;
|
||||
use rustc_expand::configure;
|
||||
use rustc_feature::Features;
|
||||
use rustc_parse::parser::ForceCollect;
|
||||
use rustc_session::utils::FlattenNonterminals;
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use smallvec::SmallVec;
|
||||
|
@ -24,17 +25,15 @@ crate fn expand(
|
|||
annotatable: Annotatable,
|
||||
) -> Vec<Annotatable> {
|
||||
check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval);
|
||||
vec![cfg_eval(ecx, annotatable)]
|
||||
vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable)]
|
||||
}
|
||||
|
||||
crate fn cfg_eval(ecx: &ExtCtxt<'_>, annotatable: Annotatable) -> Annotatable {
|
||||
CfgEval {
|
||||
cfg: &mut StripUnconfigured {
|
||||
sess: ecx.sess,
|
||||
features: ecx.ecfg.features,
|
||||
config_tokens: true,
|
||||
},
|
||||
}
|
||||
crate fn cfg_eval(
|
||||
sess: &Session,
|
||||
features: Option<&Features>,
|
||||
annotatable: Annotatable,
|
||||
) -> Annotatable {
|
||||
CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true } }
|
||||
.configure_annotatable(annotatable)
|
||||
// Since the item itself has already been configured by the `InvocationCollector`,
|
||||
// we know that fold result vector will contain exactly one element.
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
use crate::cfg_eval::cfg_eval;
|
||||
|
||||
use rustc_ast::{self as ast, attr, token, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::{attr, token, GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
|
||||
use rustc_feature::AttributeTemplate;
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::Span;
|
||||
|
||||
crate struct Expander;
|
||||
|
@ -26,8 +27,7 @@ impl MultiItemModifier for Expander {
|
|||
return ExpandResult::Ready(vec![item]);
|
||||
}
|
||||
|
||||
let item = cfg_eval(ecx, item);
|
||||
|
||||
let (sess, features) = (ecx.sess, ecx.ecfg.features);
|
||||
let result =
|
||||
ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| {
|
||||
let template =
|
||||
|
@ -40,7 +40,8 @@ impl MultiItemModifier for Expander {
|
|||
template,
|
||||
);
|
||||
|
||||
attr.meta_item_list()
|
||||
let mut resolutions: Vec<_> = attr
|
||||
.meta_item_list()
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.filter_map(|nested_meta| match nested_meta {
|
||||
|
@ -56,8 +57,21 @@ impl MultiItemModifier for Expander {
|
|||
report_path_args(sess, &meta);
|
||||
meta.path
|
||||
})
|
||||
.map(|path| (path, item.clone(), None))
|
||||
.collect()
|
||||
.map(|path| (path, dummy_annotatable(), None))
|
||||
.collect();
|
||||
|
||||
// Do not configure or clone items unless necessary.
|
||||
match &mut resolutions[..] {
|
||||
[] => {}
|
||||
[(_, first_item, _), others @ ..] => {
|
||||
*first_item = cfg_eval(sess, features, item.clone());
|
||||
for (_, item, _) in others {
|
||||
*item = first_item.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolutions
|
||||
});
|
||||
|
||||
match result {
|
||||
|
@ -67,6 +81,18 @@ impl MultiItemModifier for Expander {
|
|||
}
|
||||
}
|
||||
|
||||
// The cheapest `Annotatable` to construct.
|
||||
fn dummy_annotatable() -> Annotatable {
|
||||
Annotatable::GenericParam(ast::GenericParam {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
ident: Ident::invalid(),
|
||||
attrs: Default::default(),
|
||||
bounds: Default::default(),
|
||||
is_placeholder: false,
|
||||
kind: GenericParamKind::Lifetime,
|
||||
})
|
||||
}
|
||||
|
||||
fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
|
||||
let item_kind = match item {
|
||||
Annotatable::Item(item) => Some(&item.kind),
|
||||
|
|
|
@ -295,6 +295,8 @@ declare_features! (
|
|||
(accepted, const_fn_union, "1.56.0", Some(51909), None),
|
||||
/// Allows explicit discriminants on non-unit enum variants.
|
||||
(accepted, arbitrary_enum_discriminant, "1.56.0", Some(60553), None),
|
||||
/// Allows macro attributes to observe output of `#[derive]`.
|
||||
(accepted, macro_attributes_in_derive_output, "1.57.0", Some(81119), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: accepted features
|
||||
|
|
|
@ -592,9 +592,6 @@ declare_features! (
|
|||
/// Lessens the requirements for structs to implement `Unsize`.
|
||||
(active, relaxed_struct_unsize, "1.51.0", Some(81793), None),
|
||||
|
||||
/// Allows macro attributes to observe output of `#[derive]`.
|
||||
(active, macro_attributes_in_derive_output, "1.51.0", Some(81119), None),
|
||||
|
||||
/// Allows associated types in inherent impls.
|
||||
(incomplete, inherent_associated_types, "1.52.0", Some(8995), None),
|
||||
|
||||
|
|
|
@ -311,38 +311,6 @@ impl<'a> ResolverExpand for Resolver<'a> {
|
|||
self.create_stable_hashing_context(),
|
||||
);
|
||||
|
||||
if let Res::Def(_, _) = res {
|
||||
// Gate macro attributes in `#[derive]` output.
|
||||
if !self.session.features_untracked().macro_attributes_in_derive_output
|
||||
&& kind == MacroKind::Attr
|
||||
&& ext.builtin_name != Some(sym::derive)
|
||||
{
|
||||
let mut expn_id = parent_scope.expansion;
|
||||
loop {
|
||||
// Helper attr table is a quick way to determine whether the attr is `derive`.
|
||||
if self.helper_attrs.contains_key(&expn_id) {
|
||||
feature_err(
|
||||
&self.session.parse_sess,
|
||||
sym::macro_attributes_in_derive_output,
|
||||
path.span,
|
||||
"macro attributes in `#[derive]` output are unstable",
|
||||
)
|
||||
.emit();
|
||||
break;
|
||||
} else {
|
||||
let expn_data = expn_id.expn_data();
|
||||
match expn_data.kind {
|
||||
ExpnKind::Root
|
||||
| ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => {
|
||||
break;
|
||||
}
|
||||
_ => expn_id = expn_data.parent.expect_local(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ext)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
// gate-test-macro_attributes_in_derive_output
|
||||
// aux-build: test-macros.rs
|
||||
|
||||
#![feature(proc_macro_hygiene)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate test_macros;
|
||||
|
||||
#[derive(Empty)]
|
||||
#[empty_attr] //~ ERROR macro attributes in `#[derive]` output are unstable
|
||||
struct S1 {
|
||||
field: [u8; 10],
|
||||
}
|
||||
|
||||
#[derive(Empty)]
|
||||
#[empty_helper]
|
||||
#[empty_attr] //~ ERROR macro attributes in `#[derive]` output are unstable
|
||||
struct S2 {
|
||||
field: [u8; 10],
|
||||
}
|
||||
|
||||
#[derive(Empty)]
|
||||
struct S3 {
|
||||
field: [u8; #[identity_attr] 10], //~ ERROR macro attributes in `#[derive]` output are unstable
|
||||
}
|
||||
|
||||
#[derive(Empty)]
|
||||
struct S4 {
|
||||
field: [u8; {
|
||||
#[derive(Empty)] // OK, not gated
|
||||
struct Inner;
|
||||
10
|
||||
}]
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -1,30 +0,0 @@
|
|||
error[E0658]: macro attributes in `#[derive]` output are unstable
|
||||
--> $DIR/attribute-after-derive-feature-gate.rs:11:3
|
||||
|
|
||||
LL | #[empty_attr]
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #81119 <https://github.com/rust-lang/rust/issues/81119> for more information
|
||||
= help: add `#![feature(macro_attributes_in_derive_output)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: macro attributes in `#[derive]` output are unstable
|
||||
--> $DIR/attribute-after-derive-feature-gate.rs:18:3
|
||||
|
|
||||
LL | #[empty_attr]
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #81119 <https://github.com/rust-lang/rust/issues/81119> for more information
|
||||
= help: add `#![feature(macro_attributes_in_derive_output)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: macro attributes in `#[derive]` output are unstable
|
||||
--> $DIR/attribute-after-derive-feature-gate.rs:25:19
|
||||
|
|
||||
LL | field: [u8; #[identity_attr] 10],
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #81119 <https://github.com/rust-lang/rust/issues/81119> for more information
|
||||
= help: add `#![feature(macro_attributes_in_derive_output)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
|
@ -5,8 +5,6 @@
|
|||
// compile-flags: -Z span-debug
|
||||
// aux-build: test-macros.rs
|
||||
|
||||
#![feature(macro_attributes_in_derive_output)]
|
||||
|
||||
#![no_std] // Don't load unnecessary hygiene information from std
|
||||
extern crate std;
|
||||
|
||||
|
|
|
@ -3,35 +3,35 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
|
|||
Punct {
|
||||
ch: '#',
|
||||
spacing: Alone,
|
||||
span: $DIR/attribute-after-derive.rs:17:1: 17:2 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:15:1: 15:2 (#0),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
ident: "derive",
|
||||
span: $DIR/attribute-after-derive.rs:17:3: 17:9 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:15:3: 15:9 (#0),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
ident: "Print",
|
||||
span: $DIR/attribute-after-derive.rs:17:10: 17:15 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:15:10: 15:15 (#0),
|
||||
},
|
||||
],
|
||||
span: $DIR/attribute-after-derive.rs:17:9: 17:16 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:15:9: 15:16 (#0),
|
||||
},
|
||||
],
|
||||
span: $DIR/attribute-after-derive.rs:17:2: 17:17 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:15:2: 15:17 (#0),
|
||||
},
|
||||
Ident {
|
||||
ident: "struct",
|
||||
span: $DIR/attribute-after-derive.rs:18:1: 18:7 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:16:1: 16:7 (#0),
|
||||
},
|
||||
Ident {
|
||||
ident: "AttributeDerive",
|
||||
span: $DIR/attribute-after-derive.rs:18:8: 18:23 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:16:8: 16:23 (#0),
|
||||
},
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
|
@ -39,64 +39,64 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
|
|||
Punct {
|
||||
ch: '#',
|
||||
spacing: Alone,
|
||||
span: $DIR/attribute-after-derive.rs:19:5: 19:6 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:17:5: 17:6 (#0),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
ident: "cfg",
|
||||
span: $DIR/attribute-after-derive.rs:19:7: 19:10 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:17:7: 17:10 (#0),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
ident: "FALSE",
|
||||
span: $DIR/attribute-after-derive.rs:19:11: 19:16 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:17:11: 17:16 (#0),
|
||||
},
|
||||
],
|
||||
span: $DIR/attribute-after-derive.rs:19:10: 19:17 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:17:10: 17:17 (#0),
|
||||
},
|
||||
],
|
||||
span: $DIR/attribute-after-derive.rs:19:6: 19:18 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:17:6: 17:18 (#0),
|
||||
},
|
||||
Ident {
|
||||
ident: "field",
|
||||
span: $DIR/attribute-after-derive.rs:20:5: 20:10 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:18:5: 18:10 (#0),
|
||||
},
|
||||
Punct {
|
||||
ch: ':',
|
||||
spacing: Alone,
|
||||
span: $DIR/attribute-after-derive.rs:20:10: 20:11 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:18:10: 18:11 (#0),
|
||||
},
|
||||
Ident {
|
||||
ident: "u8",
|
||||
span: $DIR/attribute-after-derive.rs:20:12: 20:14 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:18:12: 18:14 (#0),
|
||||
},
|
||||
Punct {
|
||||
ch: ',',
|
||||
spacing: Alone,
|
||||
span: $DIR/attribute-after-derive.rs:20:14: 20:15 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:18:14: 18:15 (#0),
|
||||
},
|
||||
],
|
||||
span: $DIR/attribute-after-derive.rs:18:24: 21:2 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:16:24: 19:2 (#0),
|
||||
},
|
||||
]
|
||||
PRINT-DERIVE INPUT (DISPLAY): struct AttributeDerive { }
|
||||
PRINT-DERIVE INPUT (DEBUG): TokenStream [
|
||||
Ident {
|
||||
ident: "struct",
|
||||
span: $DIR/attribute-after-derive.rs:18:1: 18:7 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:16:1: 16:7 (#0),
|
||||
},
|
||||
Ident {
|
||||
ident: "AttributeDerive",
|
||||
span: $DIR/attribute-after-derive.rs:18:8: 18:23 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:16:8: 16:23 (#0),
|
||||
},
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
stream: TokenStream [],
|
||||
span: $DIR/attribute-after-derive.rs:18:24: 21:2 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:16:24: 19:2 (#0),
|
||||
},
|
||||
]
|
||||
PRINT-DERIVE INPUT (DISPLAY): #[print_attr] struct DeriveAttribute { }
|
||||
|
@ -104,45 +104,89 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
|
|||
Punct {
|
||||
ch: '#',
|
||||
spacing: Alone,
|
||||
span: $DIR/attribute-after-derive.rs:24:1: 24:2 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:22:1: 22:2 (#0),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
ident: "print_attr",
|
||||
span: $DIR/attribute-after-derive.rs:24:3: 24:13 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:22:3: 22:13 (#0),
|
||||
},
|
||||
],
|
||||
span: $DIR/attribute-after-derive.rs:24:2: 24:14 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:22:2: 22:14 (#0),
|
||||
},
|
||||
Ident {
|
||||
ident: "struct",
|
||||
span: $DIR/attribute-after-derive.rs:25:1: 25:7 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:23:1: 23:7 (#0),
|
||||
},
|
||||
Ident {
|
||||
ident: "DeriveAttribute",
|
||||
span: $DIR/attribute-after-derive.rs:25:8: 25:23 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:23:8: 23:23 (#0),
|
||||
},
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
stream: TokenStream [],
|
||||
span: $DIR/attribute-after-derive.rs:25:24: 28:2 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:23:24: 26:2 (#0),
|
||||
},
|
||||
]
|
||||
PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { }
|
||||
PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { #[cfg(FALSE)] field : u8, }
|
||||
PRINT-ATTR INPUT (DEBUG): TokenStream [
|
||||
Ident {
|
||||
ident: "struct",
|
||||
span: $DIR/attribute-after-derive.rs:25:1: 25:7 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:23:1: 23:7 (#0),
|
||||
},
|
||||
Ident {
|
||||
ident: "DeriveAttribute",
|
||||
span: $DIR/attribute-after-derive.rs:25:8: 25:23 (#0),
|
||||
span: $DIR/attribute-after-derive.rs:23:8: 23:23 (#0),
|
||||
},
|
||||
Group {
|
||||
delimiter: Brace,
|
||||
stream: TokenStream [],
|
||||
span: $DIR/attribute-after-derive.rs:25:24: 28:2 (#0),
|
||||
stream: TokenStream [
|
||||
Punct {
|
||||
ch: '#',
|
||||
spacing: Alone,
|
||||
span: $DIR/attribute-after-derive.rs:24:5: 24:6 (#0),
|
||||
},
|
||||
Group {
|
||||
delimiter: Bracket,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
ident: "cfg",
|
||||
span: $DIR/attribute-after-derive.rs:24:7: 24:10 (#0),
|
||||
},
|
||||
Group {
|
||||
delimiter: Parenthesis,
|
||||
stream: TokenStream [
|
||||
Ident {
|
||||
ident: "FALSE",
|
||||
span: $DIR/attribute-after-derive.rs:24:11: 24:16 (#0),
|
||||
},
|
||||
],
|
||||
span: $DIR/attribute-after-derive.rs:24:10: 24:17 (#0),
|
||||
},
|
||||
],
|
||||
span: $DIR/attribute-after-derive.rs:24:6: 24:18 (#0),
|
||||
},
|
||||
Ident {
|
||||
ident: "field",
|
||||
span: $DIR/attribute-after-derive.rs:25:5: 25:10 (#0),
|
||||
},
|
||||
Punct {
|
||||
ch: ':',
|
||||
spacing: Alone,
|
||||
span: $DIR/attribute-after-derive.rs:25:10: 25:11 (#0),
|
||||
},
|
||||
Ident {
|
||||
ident: "u8",
|
||||
span: $DIR/attribute-after-derive.rs:25:12: 25:14 (#0),
|
||||
},
|
||||
Punct {
|
||||
ch: ',',
|
||||
spacing: Alone,
|
||||
span: $DIR/attribute-after-derive.rs:25:14: 25:15 (#0),
|
||||
},
|
||||
],
|
||||
span: $DIR/attribute-after-derive.rs:23:24: 26:2 (#0),
|
||||
},
|
||||
]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue