@@ -216,6 +216,14 @@ pub struct Invocation {
216216 pub expansion_data : ExpansionData ,
217217}
218218
219+ // Needed for feature-gating attributes used after derives or together with test/bench
220+ #[ derive( Clone , Copy , PartialEq ) ]
221+ pub enum TogetherWith {
222+ None ,
223+ Derive ,
224+ TestBench ,
225+ }
226+
219227pub enum InvocationKind {
220228 Bang {
221229 mac : ast:: Mac ,
@@ -226,6 +234,7 @@ pub enum InvocationKind {
226234 attr : Option < ast:: Attribute > ,
227235 traits : Vec < Path > ,
228236 item : Annotatable ,
237+ together_with : TogetherWith ,
229238 } ,
230239 Derive {
231240 path : Path ,
@@ -353,7 +362,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
353362 let dummy = invoc. fragment_kind . dummy ( invoc. span ( ) ) . unwrap ( ) ;
354363 let fragment = self . expand_invoc ( invoc, & * ext) . unwrap_or ( dummy) ;
355364 self . collect_invocations ( fragment, & [ ] )
356- } else if let InvocationKind :: Attr { attr : None , traits, item } = invoc. kind {
365+ } else if let InvocationKind :: Attr { attr : None , traits, item, .. } = invoc. kind {
357366 if !item. derive_allowed ( ) {
358367 let attr = attr:: find_by_name ( item. attrs ( ) , "derive" )
359368 . expect ( "`derive` attribute should exist" ) ;
@@ -1069,14 +1078,23 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
10691078 attr : Option < ast:: Attribute > ,
10701079 traits : Vec < Path > ,
10711080 item : Annotatable ,
1072- kind : AstFragmentKind )
1081+ kind : AstFragmentKind ,
1082+ together_with : TogetherWith )
10731083 -> AstFragment {
1074- self . collect ( kind, InvocationKind :: Attr { attr, traits, item } )
1084+ self . collect ( kind, InvocationKind :: Attr { attr, traits, item, together_with } )
10751085 }
10761086
1077- fn find_attr_invoc ( & self , attrs : & mut Vec < ast:: Attribute > ) -> Option < ast:: Attribute > {
1087+ fn find_attr_invoc ( & self , attrs : & mut Vec < ast:: Attribute > , together_with : & mut TogetherWith )
1088+ -> Option < ast:: Attribute > {
10781089 let attr = attrs. iter ( )
1079- . position ( |a| !attr:: is_known ( a) && !is_builtin_attr ( a) )
1090+ . position ( |a| {
1091+ if a. path == "derive" {
1092+ * together_with = TogetherWith :: Derive
1093+ } else if a. path == "rustc_test_marker2" {
1094+ * together_with = TogetherWith :: TestBench
1095+ }
1096+ !attr:: is_known ( a) && !is_builtin_attr ( a)
1097+ } )
10801098 . map ( |i| attrs. remove ( i) ) ;
10811099 if let Some ( attr) = & attr {
10821100 if !self . cx . ecfg . enable_custom_inner_attributes ( ) &&
@@ -1086,14 +1104,19 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
10861104 "non-builtin inner attributes are unstable" ) ;
10871105 }
10881106 }
1107+ if together_with == & TogetherWith :: None &&
1108+ attrs. iter ( ) . any ( |a| a. path == "rustc_test_marker2" ) {
1109+ * together_with = TogetherWith :: TestBench ;
1110+ }
10891111 attr
10901112 }
10911113
10921114 /// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
1093- fn classify_item < T > ( & mut self , mut item : T ) -> ( Option < ast:: Attribute > , Vec < Path > , T )
1115+ fn classify_item < T > ( & mut self , mut item : T )
1116+ -> ( Option < ast:: Attribute > , Vec < Path > , T , TogetherWith )
10941117 where T : HasAttrs ,
10951118 {
1096- let ( mut attr, mut traits) = ( None , Vec :: new ( ) ) ;
1119+ let ( mut attr, mut traits, mut together_with ) = ( None , Vec :: new ( ) , TogetherWith :: None ) ;
10971120
10981121 item = item. map_attrs ( |mut attrs| {
10991122 if let Some ( legacy_attr_invoc) = self . cx . resolver . find_legacy_attr_invoc ( & mut attrs,
@@ -1102,19 +1125,20 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
11021125 return attrs;
11031126 }
11041127
1105- attr = self . find_attr_invoc ( & mut attrs) ;
1128+ attr = self . find_attr_invoc ( & mut attrs, & mut together_with ) ;
11061129 traits = collect_derives ( & mut self . cx , & mut attrs) ;
11071130 attrs
11081131 } ) ;
11091132
1110- ( attr, traits, item)
1133+ ( attr, traits, item, together_with )
11111134 }
11121135
11131136 /// Alternative of `classify_item()` that ignores `#[derive]` so invocations fallthrough
11141137 /// to the unused-attributes lint (making it an error on statements and expressions
11151138 /// is a breaking change)
1116- fn classify_nonitem < T : HasAttrs > ( & mut self , mut item : T ) -> ( Option < ast:: Attribute > , T ) {
1117- let mut attr = None ;
1139+ fn classify_nonitem < T : HasAttrs > ( & mut self , mut item : T )
1140+ -> ( Option < ast:: Attribute > , T , TogetherWith ) {
1141+ let ( mut attr, mut together_with) = ( None , TogetherWith :: None ) ;
11181142
11191143 item = item. map_attrs ( |mut attrs| {
11201144 if let Some ( legacy_attr_invoc) = self . cx . resolver . find_legacy_attr_invoc ( & mut attrs,
@@ -1123,11 +1147,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
11231147 return attrs;
11241148 }
11251149
1126- attr = self . find_attr_invoc ( & mut attrs) ;
1150+ attr = self . find_attr_invoc ( & mut attrs, & mut together_with ) ;
11271151 attrs
11281152 } ) ;
11291153
1130- ( attr, item)
1154+ ( attr, item, together_with )
11311155 }
11321156
11331157 fn configure < T : HasAttrs > ( & mut self , node : T ) -> Option < T > {
@@ -1166,7 +1190,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
11661190 expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
11671191
11681192 // ignore derives so they remain unused
1169- let ( attr, expr) = self . classify_nonitem ( expr) ;
1193+ let ( attr, expr, together_with ) = self . classify_nonitem ( expr) ;
11701194
11711195 if attr. is_some ( ) {
11721196 // collect the invoc regardless of whether or not attributes are permitted here
@@ -1175,7 +1199,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
11751199
11761200 // AstFragmentKind::Expr requires the macro to emit an expression
11771201 return self . collect_attr ( attr, vec ! [ ] , Annotatable :: Expr ( P ( expr) ) ,
1178- AstFragmentKind :: Expr ) . make_expr ( ) ;
1202+ AstFragmentKind :: Expr , together_with ) . make_expr ( ) ;
11791203 }
11801204
11811205 if let ast:: ExprKind :: Mac ( mac) = expr. node {
@@ -1191,14 +1215,13 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
11911215 expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
11921216
11931217 // ignore derives so they remain unused
1194- let ( attr, expr) = self . classify_nonitem ( expr) ;
1218+ let ( attr, expr, together_with ) = self . classify_nonitem ( expr) ;
11951219
11961220 if attr. is_some ( ) {
11971221 attr. as_ref ( ) . map ( |a| self . cfg . maybe_emit_expr_attr_err ( a) ) ;
11981222
11991223 return self . collect_attr ( attr, vec ! [ ] , Annotatable :: Expr ( P ( expr) ) ,
1200- AstFragmentKind :: OptExpr )
1201- . make_opt_expr ( ) ;
1224+ AstFragmentKind :: OptExpr , together_with) . make_opt_expr ( ) ;
12021225 }
12031226
12041227 if let ast:: ExprKind :: Mac ( mac) = expr. node {
@@ -1230,19 +1253,18 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
12301253
12311254 // we'll expand attributes on expressions separately
12321255 if !stmt. is_expr ( ) {
1233- let ( attr, derives, stmt_) = if stmt. is_item ( ) {
1256+ let ( attr, derives, stmt_, together_with ) = if stmt. is_item ( ) {
12341257 self . classify_item ( stmt)
12351258 } else {
12361259 // ignore derives on non-item statements so it falls through
12371260 // to the unused-attributes lint
1238- let ( attr, stmt) = self . classify_nonitem ( stmt) ;
1239- ( attr, vec ! [ ] , stmt)
1261+ let ( attr, stmt, together_with ) = self . classify_nonitem ( stmt) ;
1262+ ( attr, vec ! [ ] , stmt, together_with )
12401263 } ;
12411264
12421265 if attr. is_some ( ) || !derives. is_empty ( ) {
1243- return self . collect_attr ( attr, derives,
1244- Annotatable :: Stmt ( P ( stmt_) ) , AstFragmentKind :: Stmts )
1245- . make_stmts ( ) ;
1266+ return self . collect_attr ( attr, derives, Annotatable :: Stmt ( P ( stmt_) ) ,
1267+ AstFragmentKind :: Stmts , together_with) . make_stmts ( ) ;
12461268 }
12471269
12481270 stmt = stmt_;
@@ -1284,10 +1306,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
12841306 fn fold_item ( & mut self , item : P < ast:: Item > ) -> OneVector < P < ast:: Item > > {
12851307 let item = configure ! ( self , item) ;
12861308
1287- let ( attr, traits, item) = self . classify_item ( item) ;
1309+ let ( attr, traits, item, together_with ) = self . classify_item ( item) ;
12881310 if attr. is_some ( ) || !traits. is_empty ( ) {
1289- let item = Annotatable :: Item ( item) ;
1290- return self . collect_attr ( attr , traits , item , AstFragmentKind :: Items ) . make_items ( ) ;
1311+ return self . collect_attr ( attr , traits , Annotatable :: Item ( item) ,
1312+ AstFragmentKind :: Items , together_with ) . make_items ( ) ;
12911313 }
12921314
12931315 match item. node {
@@ -1359,11 +1381,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
13591381 fn fold_trait_item ( & mut self , item : ast:: TraitItem ) -> OneVector < ast:: TraitItem > {
13601382 let item = configure ! ( self , item) ;
13611383
1362- let ( attr, traits, item) = self . classify_item ( item) ;
1384+ let ( attr, traits, item, together_with ) = self . classify_item ( item) ;
13631385 if attr. is_some ( ) || !traits. is_empty ( ) {
1364- let item = Annotatable :: TraitItem ( P ( item) ) ;
1365- return self . collect_attr ( attr, traits, item, AstFragmentKind :: TraitItems )
1366- . make_trait_items ( )
1386+ return self . collect_attr ( attr, traits, Annotatable :: TraitItem ( P ( item) ) ,
1387+ AstFragmentKind :: TraitItems , together_with) . make_trait_items ( )
13671388 }
13681389
13691390 match item. node {
@@ -1379,11 +1400,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
13791400 fn fold_impl_item ( & mut self , item : ast:: ImplItem ) -> OneVector < ast:: ImplItem > {
13801401 let item = configure ! ( self , item) ;
13811402
1382- let ( attr, traits, item) = self . classify_item ( item) ;
1403+ let ( attr, traits, item, together_with ) = self . classify_item ( item) ;
13831404 if attr. is_some ( ) || !traits. is_empty ( ) {
1384- let item = Annotatable :: ImplItem ( P ( item) ) ;
1385- return self . collect_attr ( attr, traits, item, AstFragmentKind :: ImplItems )
1386- . make_impl_items ( ) ;
1405+ return self . collect_attr ( attr, traits, Annotatable :: ImplItem ( P ( item) ) ,
1406+ AstFragmentKind :: ImplItems , together_with) . make_impl_items ( ) ;
13871407 }
13881408
13891409 match item. node {
@@ -1414,12 +1434,12 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
14141434
14151435 fn fold_foreign_item ( & mut self ,
14161436 foreign_item : ast:: ForeignItem ) -> OneVector < ast:: ForeignItem > {
1417- let ( attr, traits, foreign_item) = self . classify_item ( foreign_item) ;
1437+ let ( attr, traits, foreign_item, together_with ) = self . classify_item ( foreign_item) ;
14181438
14191439 if attr. is_some ( ) || !traits. is_empty ( ) {
1420- let item = Annotatable :: ForeignItem ( P ( foreign_item) ) ;
1421- return self . collect_attr ( attr , traits , item , AstFragmentKind :: ForeignItems )
1422- . make_foreign_items ( ) ;
1440+ return self . collect_attr ( attr , traits , Annotatable :: ForeignItem ( P ( foreign_item) ) ,
1441+ AstFragmentKind :: ForeignItems , together_with )
1442+ . make_foreign_items ( ) ;
14231443 }
14241444
14251445 if let ast:: ForeignItemKind :: Macro ( mac) = foreign_item. node {
0 commit comments