diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 5a4737842f0a..10c19ea105e4 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -301,6 +301,8 @@ pub enum InvocationKind { }, Attr { attr: ast::Attribute, + // Re-insertion position for inert attributes. + pos: usize, item: Annotatable, // Required for resolving derive helper attributes. derives: Vec, @@ -690,7 +692,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } _ => unreachable!(), }, - InvocationKind::Attr { attr, mut item, derives } => match ext { + InvocationKind::Attr { attr, pos, mut item, derives } => match ext { SyntaxExtensionKind::Attr(expander) => { self.gate_proc_macro_input(&item); self.gate_proc_macro_attr_item(span, &item); @@ -721,7 +723,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ExpandResult::Retry(item) => { // Reassemble the original invocation for retrying. return ExpandResult::Retry(Invocation { - kind: InvocationKind::Attr { attr, item, derives }, + kind: InvocationKind::Attr { attr, pos, item, derives }, ..invoc }); } @@ -739,7 +741,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { if *mark_used { self.cx.sess.mark_attr_used(&attr); } - item.visit_attrs(|attrs| attrs.push(attr)); + item.visit_attrs(|attrs| attrs.insert(pos, attr)); fragment_kind.expect_from_annotatables(iter::once(item)) } _ => unreachable!(), @@ -1000,17 +1002,20 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect_attr( &mut self, - (attr, derives): (ast::Attribute, Vec), + (attr, pos, derives): (ast::Attribute, usize, Vec), item: Annotatable, kind: AstFragmentKind, ) -> AstFragment { - self.collect(kind, InvocationKind::Attr { attr, item, derives }) + self.collect(kind, InvocationKind::Attr { attr, pos, item, derives }) } /// If `item` is an attribute invocation, remove the attribute and return it together with - /// derives following it. We have to collect the derives in order to resolve legacy derive - /// helpers (helpers written before derives that introduce them). - fn take_first_attr(&mut self, item: &mut impl HasAttrs) -> Option<(ast::Attribute, Vec)> { + /// its position and derives following it. We have to collect the derives in order to resolve + /// legacy derive helpers (helpers written before derives that introduce them). + fn take_first_attr( + &mut self, + item: &mut impl HasAttrs, + ) -> Option<(ast::Attribute, usize, Vec)> { let mut attr = None; item.visit_attrs(|attrs| { @@ -1033,7 +1038,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { }) .collect(); - (attr, following_derives) + (attr, attr_pos, following_derives) }) }); diff --git a/src/test/ui/proc-macro/auxiliary/test-macros.rs b/src/test/ui/proc-macro/auxiliary/test-macros.rs index 57a7ffa39ef0..a7ed4bc88250 100644 --- a/src/test/ui/proc-macro/auxiliary/test-macros.rs +++ b/src/test/ui/proc-macro/auxiliary/test-macros.rs @@ -7,7 +7,7 @@ #![crate_type = "proc-macro"] extern crate proc_macro; -use proc_macro::TokenStream; +use proc_macro::{TokenStream, TokenTree}; // Macro that return empty token stream. @@ -80,6 +80,10 @@ pub fn recollect_derive(input: TokenStream) -> TokenStream { // Macros that print their input in the original and re-collected forms (if they differ). fn print_helper(input: TokenStream, kind: &str) -> TokenStream { + print_helper_ext(input, kind, true) +} + +fn print_helper_ext(input: TokenStream, kind: &str, debug: bool) -> TokenStream { let input_display = format!("{}", input); let input_debug = format!("{:#?}", input); let recollected = input.into_iter().collect(); @@ -89,9 +93,11 @@ fn print_helper(input: TokenStream, kind: &str) -> TokenStream { if recollected_display != input_display { println!("PRINT-{} RE-COLLECTED (DISPLAY): {}", kind, recollected_display); } - println!("PRINT-{} INPUT (DEBUG): {}", kind, input_debug); - if recollected_debug != input_debug { - println!("PRINT-{} RE-COLLECTED (DEBUG): {}", kind, recollected_debug); + if debug { + println!("PRINT-{} INPUT (DEBUG): {}", kind, input_debug); + if recollected_debug != input_debug { + println!("PRINT-{} RE-COLLECTED (DEBUG): {}", kind, recollected_debug); + } } recollected } @@ -108,8 +114,12 @@ pub fn print_bang_consume(input: TokenStream) -> TokenStream { } #[proc_macro_attribute] -pub fn print_attr(_: TokenStream, input: TokenStream) -> TokenStream { - print_helper(input, "ATTR") +pub fn print_attr(args: TokenStream, input: TokenStream) -> TokenStream { + let debug = match &args.into_iter().collect::>()[..] { + [TokenTree::Ident(ident)] if ident.to_string() == "nodebug" => false, + _ => true, + }; + print_helper_ext(input, "ATTR", debug) } #[proc_macro_attribute] diff --git a/src/test/ui/proc-macro/derive-helper-legacy-spurious.rs b/src/test/ui/proc-macro/derive-helper-legacy-spurious.rs new file mode 100644 index 000000000000..4a7e48eed46c --- /dev/null +++ b/src/test/ui/proc-macro/derive-helper-legacy-spurious.rs @@ -0,0 +1,12 @@ +// aux-build:test-macros.rs + +#![dummy] //~ ERROR cannot find attribute `dummy` in this scope + +#[macro_use] +extern crate test_macros; + +#[derive(Empty)] //~ ERROR cannot determine resolution for the attribute macro `derive` +#[empty_helper] //~ ERROR cannot find attribute `empty_helper` in this scope +struct Foo {} + +fn main() {} diff --git a/src/test/ui/proc-macro/derive-helper-legacy-spurious.stderr b/src/test/ui/proc-macro/derive-helper-legacy-spurious.stderr new file mode 100644 index 000000000000..fd1ed8a3d0ff --- /dev/null +++ b/src/test/ui/proc-macro/derive-helper-legacy-spurious.stderr @@ -0,0 +1,22 @@ +error: cannot find attribute `dummy` in this scope + --> $DIR/derive-helper-legacy-spurious.rs:3:4 + | +LL | #![dummy] + | ^^^^^ + +error: cannot determine resolution for the attribute macro `derive` + --> $DIR/derive-helper-legacy-spurious.rs:8:3 + | +LL | #[derive(Empty)] + | ^^^^^^ + | + = note: import resolution is stuck, try simplifying macro imports + +error: cannot find attribute `empty_helper` in this scope + --> $DIR/derive-helper-legacy-spurious.rs:9:3 + | +LL | #[empty_helper] + | ^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/proc-macro/inert-attribute-order.rs b/src/test/ui/proc-macro/inert-attribute-order.rs new file mode 100644 index 000000000000..f80796756411 --- /dev/null +++ b/src/test/ui/proc-macro/inert-attribute-order.rs @@ -0,0 +1,23 @@ +// Order of inert attributes, both built-in and custom is preserved during expansion. + +// check-pass +// compile-flags: -Z span-debug +// aux-build:test-macros.rs + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +#[macro_use] +extern crate test_macros; + +/// 1 +#[rustfmt::attr2] +#[doc = "3"] +#[print_attr(nodebug)] +#[doc = "4"] +#[rustfmt::attr5] +/// 6 +#[print_attr(nodebug)] +struct S; + +fn main() {} diff --git a/src/test/ui/proc-macro/inert-attribute-order.stdout b/src/test/ui/proc-macro/inert-attribute-order.stdout new file mode 100644 index 000000000000..cc215545952d --- /dev/null +++ b/src/test/ui/proc-macro/inert-attribute-order.stdout @@ -0,0 +1,7 @@ +PRINT-ATTR INPUT (DISPLAY): /// 1 +#[rustfmt :: attr2] #[doc = "3"] #[doc = "4"] #[rustfmt :: attr5] /// 6 +#[print_attr(nodebug)] struct S ; +PRINT-ATTR RE-COLLECTED (DISPLAY): #[doc = " 1"] #[rustfmt :: attr2] #[doc = "3"] #[doc = "4"] +#[rustfmt :: attr5] #[doc = " 6"] #[print_attr(nodebug)] struct S ; +PRINT-ATTR INPUT (DISPLAY): #[doc = " 1"] #[rustfmt :: attr2] #[doc = "3"] #[doc = "4"] +#[rustfmt :: attr5] #[doc = " 6"] struct S ; diff --git a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout index 19aa4dfb60e3..15e63c20eb9b 100644 --- a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout +++ b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout @@ -1,4 +1,4 @@ -PRINT-ATTR INPUT (DISPLAY): #[allow(dead_code)] #[derive(Print)] #[print_helper(b)] #[print_helper(a)] +PRINT-ATTR INPUT (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[derive(Print)] #[print_helper(b)] struct Foo < #[cfg(FALSE)] A, B > { #[cfg(FALSE)] first : String, #[cfg_attr(FALSE, deny(warnings))] second : @@ -23,6 +23,31 @@ struct Foo < #[cfg(FALSE)] A, B > }], #[print_helper(d)] fourth : B } PRINT-ATTR INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:16:1: 16:2 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:16:3: 16:15 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "a", + span: $DIR/issue-75930-derive-cfg.rs:16:16: 16:17 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:16:15: 16:18 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:16:2: 16:19 (#0), + }, Punct { ch: '#', spacing: Alone, @@ -98,31 +123,6 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ ], span: $DIR/issue-75930-derive-cfg.rs:21:2: 21:19 (#0), }, - Punct { - ch: '#', - spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:16:1: 16:2 (#0), - }, - Group { - delimiter: Bracket, - stream: TokenStream [ - Ident { - ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:16:3: 16:15 (#0), - }, - Group { - delimiter: Parenthesis, - stream: TokenStream [ - Ident { - ident: "a", - span: $DIR/issue-75930-derive-cfg.rs:16:16: 16:17 (#0), - }, - ], - span: $DIR/issue-75930-derive-cfg.rs:16:15: 16:18 (#0), - }, - ], - span: $DIR/issue-75930-derive-cfg.rs:16:2: 16:19 (#0), - }, Ident { ident: "struct", span: $DIR/issue-75930-derive-cfg.rs:22:1: 22:7 (#0), @@ -1194,7 +1194,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: $DIR/issue-75930-derive-cfg.rs:22:32: 65:2 (#0), }, ] -PRINT-DERIVE INPUT (DISPLAY): #[allow(dead_code)] #[print_helper(b)] #[print_helper(a)] struct Foo < B > +PRINT-DERIVE INPUT (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[print_helper(b)] struct Foo < B > { second : bool, third : [u8 ; @@ -1217,14 +1217,14 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ delimiter: Bracket, stream: TokenStream [ Ident { - ident: "allow", + ident: "print_helper", span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "dead_code", + ident: "a", span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0), }, ], @@ -1242,14 +1242,14 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ delimiter: Bracket, stream: TokenStream [ Ident { - ident: "print_helper", + ident: "allow", span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "b", + ident: "dead_code", span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0), }, ], @@ -1274,7 +1274,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ delimiter: Parenthesis, stream: TokenStream [ Ident { - ident: "a", + ident: "b", span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0), }, ],