diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 4f38e060023..2d0009c225c 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -634,6 +634,10 @@ declare_features! ( /// Lessens the requirements for structs to implement `Unsize`. (active, relaxed_struct_unsize, "1.51.0", Some(1), None), + + /// Allows macro attributes to observe output of `#[derive]`. + (active, macro_attributes_in_derive_output, "1.51.0", Some(81119), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 6d3fde33f4d..f7010ca94bd 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -280,6 +280,36 @@ impl<'a> ResolverExpand for Resolver<'a> { if let Res::Def(_, _) = res { let normal_module_def_id = self.macro_def_scope(invoc_id).nearest_parent_mod; self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id); + + // 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, + } + } + } + } } Ok(ext) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 86f8061a24a..20e4f7262ac 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -679,6 +679,7 @@ symbols! { loop_break_value, lt, macro_at_most_once_rep, + macro_attributes_in_derive_output, macro_escape, macro_export, macro_lifetime_matcher, diff --git a/src/test/ui/proc-macro/attribute-after-derive-feature-gate.rs b/src/test/ui/proc-macro/attribute-after-derive-feature-gate.rs new file mode 100644 index 00000000000..74751a23d79 --- /dev/null +++ b/src/test/ui/proc-macro/attribute-after-derive-feature-gate.rs @@ -0,0 +1,28 @@ +// 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 +} + +fn main() {} diff --git a/src/test/ui/proc-macro/attribute-after-derive-feature-gate.stderr b/src/test/ui/proc-macro/attribute-after-derive-feature-gate.stderr new file mode 100644 index 00000000000..74cace628b9 --- /dev/null +++ b/src/test/ui/proc-macro/attribute-after-derive-feature-gate.stderr @@ -0,0 +1,30 @@ +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 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 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 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`. diff --git a/src/test/ui/proc-macro/attribute-after-derive.rs b/src/test/ui/proc-macro/attribute-after-derive.rs index 0f0f27bff97..ac3f28b6ef3 100644 --- a/src/test/ui/proc-macro/attribute-after-derive.rs +++ b/src/test/ui/proc-macro/attribute-after-derive.rs @@ -5,6 +5,8 @@ // 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; diff --git a/src/test/ui/proc-macro/attribute-after-derive.stdout b/src/test/ui/proc-macro/attribute-after-derive.stdout index 78c58c0a32f..11f49235327 100644 --- a/src/test/ui/proc-macro/attribute-after-derive.stdout +++ b/src/test/ui/proc-macro/attribute-after-derive.stdout @@ -3,35 +3,35 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/attribute-after-derive.rs:15:1: 15:2 (#0), + span: $DIR/attribute-after-derive.rs:17:1: 17:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "derive", - span: $DIR/attribute-after-derive.rs:15:3: 15:9 (#0), + span: $DIR/attribute-after-derive.rs:17:3: 17:9 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "Print", - span: $DIR/attribute-after-derive.rs:15:10: 15:15 (#0), + span: $DIR/attribute-after-derive.rs:17:10: 17:15 (#0), }, ], - span: $DIR/attribute-after-derive.rs:15:9: 15:16 (#0), + span: $DIR/attribute-after-derive.rs:17:9: 17:16 (#0), }, ], - span: $DIR/attribute-after-derive.rs:15:2: 15:17 (#0), + span: $DIR/attribute-after-derive.rs:17:2: 17:17 (#0), }, Ident { ident: "struct", - span: $DIR/attribute-after-derive.rs:16:1: 16:7 (#0), + span: $DIR/attribute-after-derive.rs:18:1: 18:7 (#0), }, Ident { ident: "AttributeDerive", - span: $DIR/attribute-after-derive.rs:16:8: 16:23 (#0), + span: $DIR/attribute-after-derive.rs:18:8: 18:23 (#0), }, Group { delimiter: Brace, @@ -39,80 +39,80 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/attribute-after-derive.rs:17:5: 17:6 (#0), + span: $DIR/attribute-after-derive.rs:19:5: 19:6 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/attribute-after-derive.rs:17:7: 17:10 (#0), + span: $DIR/attribute-after-derive.rs:19:7: 19:10 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/attribute-after-derive.rs:17:11: 17:16 (#0), + span: $DIR/attribute-after-derive.rs:19:11: 19:16 (#0), }, ], - span: $DIR/attribute-after-derive.rs:17:10: 17:17 (#0), + span: $DIR/attribute-after-derive.rs:19:10: 19:17 (#0), }, ], - span: $DIR/attribute-after-derive.rs:17:6: 17:18 (#0), + span: $DIR/attribute-after-derive.rs:19:6: 19:18 (#0), }, Ident { ident: "field", - span: $DIR/attribute-after-derive.rs:18:5: 18:10 (#0), + span: $DIR/attribute-after-derive.rs:20:5: 20:10 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/attribute-after-derive.rs:18:10: 18:11 (#0), + span: $DIR/attribute-after-derive.rs:20:10: 20:11 (#0), }, Ident { ident: "u8", - span: $DIR/attribute-after-derive.rs:18:12: 18:14 (#0), + span: $DIR/attribute-after-derive.rs:20:12: 20:14 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/attribute-after-derive.rs:18:14: 18:15 (#0), + span: $DIR/attribute-after-derive.rs:20:14: 20:15 (#0), }, ], - span: $DIR/attribute-after-derive.rs:16:24: 19:2 (#0), + span: $DIR/attribute-after-derive.rs:18:24: 21:2 (#0), }, ] PRINT-DERIVE INPUT (DISPLAY): struct AttributeDerive { } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/attribute-after-derive.rs:16:1: 19:2 (#0), + span: $DIR/attribute-after-derive.rs:18:1: 21:2 (#0), }, Ident { ident: "AttributeDerive", - span: $DIR/attribute-after-derive.rs:16:1: 19:2 (#0), + span: $DIR/attribute-after-derive.rs:18:1: 21:2 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/attribute-after-derive.rs:16:1: 19:2 (#0), + span: $DIR/attribute-after-derive.rs:18:1: 21:2 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { } PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0), + span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0), }, Ident { ident: "DeriveAttribute", - span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0), + span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0), + span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0), }, ] PRINT-DERIVE INPUT (DISPLAY): #[print_attr] struct DeriveAttribute { } @@ -120,29 +120,29 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0), + span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_attr", - span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0), + span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0), }, ], - span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0), + span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0), }, Ident { ident: "struct", - span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0), + span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0), }, Ident { ident: "DeriveAttribute", - span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0), + span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/attribute-after-derive.rs:23:1: 26:2 (#0), + span: $DIR/attribute-after-derive.rs:25:1: 28:2 (#0), }, ]