expand: Preserve order of inert attributes during expansion

This commit is contained in:
Vadim Petrochenkov 2021-02-23 00:54:09 +03:00
parent c02d21033d
commit fc9d578bc5
5 changed files with 75 additions and 77 deletions

View file

@ -301,6 +301,8 @@ pub enum InvocationKind {
}, },
Attr { Attr {
attr: ast::Attribute, attr: ast::Attribute,
// Re-insertion position for inert attributes.
pos: usize,
item: Annotatable, item: Annotatable,
// Required for resolving derive helper attributes. // Required for resolving derive helper attributes.
derives: Vec<Path>, derives: Vec<Path>,
@ -690,7 +692,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
InvocationKind::Attr { attr, mut item, derives } => match ext { InvocationKind::Attr { attr, pos, mut item, derives } => match ext {
SyntaxExtensionKind::Attr(expander) => { SyntaxExtensionKind::Attr(expander) => {
self.gate_proc_macro_input(&item); self.gate_proc_macro_input(&item);
self.gate_proc_macro_attr_item(span, &item); self.gate_proc_macro_attr_item(span, &item);
@ -721,7 +723,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
ExpandResult::Retry(item) => { ExpandResult::Retry(item) => {
// Reassemble the original invocation for retrying. // Reassemble the original invocation for retrying.
return ExpandResult::Retry(Invocation { return ExpandResult::Retry(Invocation {
kind: InvocationKind::Attr { attr, item, derives }, kind: InvocationKind::Attr { attr, pos, item, derives },
..invoc ..invoc
}); });
} }
@ -739,7 +741,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
if *mark_used { if *mark_used {
self.cx.sess.mark_attr_used(&attr); 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)) fragment_kind.expect_from_annotatables(iter::once(item))
} }
_ => unreachable!(), _ => unreachable!(),
@ -1000,17 +1002,20 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
fn collect_attr( fn collect_attr(
&mut self, &mut self,
(attr, derives): (ast::Attribute, Vec<Path>), (attr, pos, derives): (ast::Attribute, usize, Vec<Path>),
item: Annotatable, item: Annotatable,
kind: AstFragmentKind, kind: AstFragmentKind,
) -> AstFragment { ) -> 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 /// 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 /// its position and derives following it. We have to collect the derives in order to resolve
/// helpers (helpers written before derives that introduce them). /// legacy derive helpers (helpers written before derives that introduce them).
fn take_first_attr(&mut self, item: &mut impl HasAttrs) -> Option<(ast::Attribute, Vec<Path>)> { fn take_first_attr(
&mut self,
item: &mut impl HasAttrs,
) -> Option<(ast::Attribute, usize, Vec<Path>)> {
let mut attr = None; let mut attr = None;
item.visit_attrs(|attrs| { item.visit_attrs(|attrs| {
@ -1033,7 +1038,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
}) })
.collect(); .collect();
(attr, following_derives) (attr, attr_pos, following_derives)
}) })
}); });

View file

@ -6,8 +6,7 @@
extern crate test_macros; extern crate test_macros;
#[derive(Empty)] //~ ERROR cannot determine resolution for the attribute macro `derive` #[derive(Empty)] //~ ERROR cannot determine resolution for the attribute macro `derive`
#[empty_helper] //~ WARN derive helper attribute is used before it is introduced #[empty_helper] //~ ERROR cannot find attribute `empty_helper` in this scope
//~| WARN this was previously accepted
struct Foo {} struct Foo {}
fn main() {} fn main() {}

View file

@ -12,17 +12,11 @@ LL | #[derive(Empty)]
| |
= note: import resolution is stuck, try simplifying macro imports = note: import resolution is stuck, try simplifying macro imports
warning: derive helper attribute is used before it is introduced error: cannot find attribute `empty_helper` in this scope
--> $DIR/derive-helper-legacy-spurious.rs:9:3 --> $DIR/derive-helper-legacy-spurious.rs:9:3
| |
LL | #[derive(Empty)]
| ----- the attribute is introduced here
LL | #[empty_helper] LL | #[empty_helper]
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
|
= note: `#[warn(legacy_derive_helpers)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #79202 <https://github.com/rust-lang/rust/issues/79202>
error: aborting due to 2 previous errors; 1 warning emitted error: aborting due to 3 previous errors

View file

@ -1,7 +1,7 @@
PRINT-ATTR INPUT (DISPLAY): /// 1 PRINT-ATTR INPUT (DISPLAY): /// 1
#[doc = "3"] #[doc = "4"] #[rustfmt :: attr5] /// 6 #[rustfmt :: attr2] #[doc = "3"] #[doc = "4"] #[rustfmt :: attr5] /// 6
#[print_attr(nodebug)] #[rustfmt :: attr2] struct S ; #[print_attr(nodebug)] struct S ;
PRINT-ATTR RE-COLLECTED (DISPLAY): #[doc = " 1"] #[doc = "3"] #[doc = "4"] #[rustfmt :: attr5] #[doc = " 6"] PRINT-ATTR RE-COLLECTED (DISPLAY): #[doc = " 1"] #[rustfmt :: attr2] #[doc = "3"] #[doc = "4"]
#[print_attr(nodebug)] #[rustfmt :: attr2] struct S ; #[rustfmt :: attr5] #[doc = " 6"] #[print_attr(nodebug)] struct S ;
PRINT-ATTR INPUT (DISPLAY): #[doc = " 1"] #[doc = "3"] #[doc = "4"] #[doc = " 6"] #[rustfmt :: attr2] PRINT-ATTR INPUT (DISPLAY): #[doc = " 1"] #[rustfmt :: attr2] #[doc = "3"] #[doc = "4"]
#[rustfmt :: attr5] struct S ; #[rustfmt :: attr5] #[doc = " 6"] struct S ;

View file

@ -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 > struct Foo < #[cfg(FALSE)] A, B >
{ {
#[cfg(FALSE)] first : String, #[cfg_attr(FALSE, deny(warnings))] second : #[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_helper(d)] fourth : B
} }
PRINT-ATTR INPUT (DEBUG): TokenStream [ 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 { Punct {
ch: '#', ch: '#',
spacing: Alone, spacing: Alone,
@ -98,31 +123,6 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
], ],
span: $DIR/issue-75930-derive-cfg.rs:21:2: 21:19 (#0), 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 {
ident: "struct", ident: "struct",
span: $DIR/issue-75930-derive-cfg.rs:22:1: 22:7 (#0), 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), 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 : second : bool, third :
[u8 ; [u8 ;
@ -1208,6 +1208,31 @@ PRINT-DERIVE INPUT (DISPLAY): #[allow(dead_code)] #[print_helper(b)] #[print_hel
}], #[print_helper(d)] fourth : B, }], #[print_helper(d)] fourth : B,
} }
PRINT-DERIVE INPUT (DEBUG): TokenStream [ PRINT-DERIVE INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
spacing: Alone,
span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "print_helper",
span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "a",
span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
},
],
span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
},
],
span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
},
Punct { Punct {
ch: '#', ch: '#',
spacing: Alone, spacing: Alone,
@ -1258,31 +1283,6 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
], ],
span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0), span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
}, },
Punct {
ch: '#',
spacing: Alone,
span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "print_helper",
span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "a",
span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
},
],
span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
},
],
span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),
},
Ident { Ident {
ident: "struct", ident: "struct",
span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0), span: $DIR/issue-75930-derive-cfg.rs:22:1: 65:2 (#0),