@@ -216,6 +216,14 @@ pub struct Invocation {
216
216
pub expansion_data : ExpansionData ,
217
217
}
218
218
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
+
219
227
pub enum InvocationKind {
220
228
Bang {
221
229
mac : ast:: Mac ,
@@ -226,6 +234,7 @@ pub enum InvocationKind {
226
234
attr : Option < ast:: Attribute > ,
227
235
traits : Vec < Path > ,
228
236
item : Annotatable ,
237
+ together_with : TogetherWith ,
229
238
} ,
230
239
Derive {
231
240
path : Path ,
@@ -353,7 +362,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
353
362
let dummy = invoc. fragment_kind . dummy ( invoc. span ( ) ) . unwrap ( ) ;
354
363
let fragment = self . expand_invoc ( invoc, & * ext) . unwrap_or ( dummy) ;
355
364
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 {
357
366
if !item. derive_allowed ( ) {
358
367
let attr = attr:: find_by_name ( item. attrs ( ) , "derive" )
359
368
. expect ( "`derive` attribute should exist" ) ;
@@ -1069,14 +1078,23 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
1069
1078
attr : Option < ast:: Attribute > ,
1070
1079
traits : Vec < Path > ,
1071
1080
item : Annotatable ,
1072
- kind : AstFragmentKind )
1081
+ kind : AstFragmentKind ,
1082
+ together_with : TogetherWith )
1073
1083
-> AstFragment {
1074
- self . collect ( kind, InvocationKind :: Attr { attr, traits, item } )
1084
+ self . collect ( kind, InvocationKind :: Attr { attr, traits, item, together_with } )
1075
1085
}
1076
1086
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 > {
1078
1089
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
+ } )
1080
1098
. map ( |i| attrs. remove ( i) ) ;
1081
1099
if let Some ( attr) = & attr {
1082
1100
if !self . cx . ecfg . enable_custom_inner_attributes ( ) &&
@@ -1086,14 +1104,19 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
1086
1104
"non-builtin inner attributes are unstable" ) ;
1087
1105
}
1088
1106
}
1107
+ if together_with == & TogetherWith :: None &&
1108
+ attrs. iter ( ) . any ( |a| a. path == "rustc_test_marker2" ) {
1109
+ * together_with = TogetherWith :: TestBench ;
1110
+ }
1089
1111
attr
1090
1112
}
1091
1113
1092
1114
/// 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 )
1094
1117
where T : HasAttrs ,
1095
1118
{
1096
- let ( mut attr, mut traits) = ( None , Vec :: new ( ) ) ;
1119
+ let ( mut attr, mut traits, mut together_with ) = ( None , Vec :: new ( ) , TogetherWith :: None ) ;
1097
1120
1098
1121
item = item. map_attrs ( |mut attrs| {
1099
1122
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> {
1102
1125
return attrs;
1103
1126
}
1104
1127
1105
- attr = self . find_attr_invoc ( & mut attrs) ;
1128
+ attr = self . find_attr_invoc ( & mut attrs, & mut together_with ) ;
1106
1129
traits = collect_derives ( & mut self . cx , & mut attrs) ;
1107
1130
attrs
1108
1131
} ) ;
1109
1132
1110
- ( attr, traits, item)
1133
+ ( attr, traits, item, together_with )
1111
1134
}
1112
1135
1113
1136
/// Alternative of `classify_item()` that ignores `#[derive]` so invocations fallthrough
1114
1137
/// to the unused-attributes lint (making it an error on statements and expressions
1115
1138
/// 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 ) ;
1118
1142
1119
1143
item = item. map_attrs ( |mut attrs| {
1120
1144
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> {
1123
1147
return attrs;
1124
1148
}
1125
1149
1126
- attr = self . find_attr_invoc ( & mut attrs) ;
1150
+ attr = self . find_attr_invoc ( & mut attrs, & mut together_with ) ;
1127
1151
attrs
1128
1152
} ) ;
1129
1153
1130
- ( attr, item)
1154
+ ( attr, item, together_with )
1131
1155
}
1132
1156
1133
1157
fn configure < T : HasAttrs > ( & mut self , node : T ) -> Option < T > {
@@ -1166,7 +1190,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
1166
1190
expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
1167
1191
1168
1192
// ignore derives so they remain unused
1169
- let ( attr, expr) = self . classify_nonitem ( expr) ;
1193
+ let ( attr, expr, together_with ) = self . classify_nonitem ( expr) ;
1170
1194
1171
1195
if attr. is_some ( ) {
1172
1196
// collect the invoc regardless of whether or not attributes are permitted here
@@ -1175,7 +1199,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
1175
1199
1176
1200
// AstFragmentKind::Expr requires the macro to emit an expression
1177
1201
return self . collect_attr ( attr, vec ! [ ] , Annotatable :: Expr ( P ( expr) ) ,
1178
- AstFragmentKind :: Expr ) . make_expr ( ) ;
1202
+ AstFragmentKind :: Expr , together_with ) . make_expr ( ) ;
1179
1203
}
1180
1204
1181
1205
if let ast:: ExprKind :: Mac ( mac) = expr. node {
@@ -1191,14 +1215,13 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
1191
1215
expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
1192
1216
1193
1217
// ignore derives so they remain unused
1194
- let ( attr, expr) = self . classify_nonitem ( expr) ;
1218
+ let ( attr, expr, together_with ) = self . classify_nonitem ( expr) ;
1195
1219
1196
1220
if attr. is_some ( ) {
1197
1221
attr. as_ref ( ) . map ( |a| self . cfg . maybe_emit_expr_attr_err ( a) ) ;
1198
1222
1199
1223
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 ( ) ;
1202
1225
}
1203
1226
1204
1227
if let ast:: ExprKind :: Mac ( mac) = expr. node {
@@ -1230,19 +1253,18 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
1230
1253
1231
1254
// we'll expand attributes on expressions separately
1232
1255
if !stmt. is_expr ( ) {
1233
- let ( attr, derives, stmt_) = if stmt. is_item ( ) {
1256
+ let ( attr, derives, stmt_, together_with ) = if stmt. is_item ( ) {
1234
1257
self . classify_item ( stmt)
1235
1258
} else {
1236
1259
// ignore derives on non-item statements so it falls through
1237
1260
// 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 )
1240
1263
} ;
1241
1264
1242
1265
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 ( ) ;
1246
1268
}
1247
1269
1248
1270
stmt = stmt_;
@@ -1284,10 +1306,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
1284
1306
fn fold_item ( & mut self , item : P < ast:: Item > ) -> OneVector < P < ast:: Item > > {
1285
1307
let item = configure ! ( self , item) ;
1286
1308
1287
- let ( attr, traits, item) = self . classify_item ( item) ;
1309
+ let ( attr, traits, item, together_with ) = self . classify_item ( item) ;
1288
1310
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 ( ) ;
1291
1313
}
1292
1314
1293
1315
match item. node {
@@ -1359,11 +1381,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
1359
1381
fn fold_trait_item ( & mut self , item : ast:: TraitItem ) -> OneVector < ast:: TraitItem > {
1360
1382
let item = configure ! ( self , item) ;
1361
1383
1362
- let ( attr, traits, item) = self . classify_item ( item) ;
1384
+ let ( attr, traits, item, together_with ) = self . classify_item ( item) ;
1363
1385
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 ( )
1367
1388
}
1368
1389
1369
1390
match item. node {
@@ -1379,11 +1400,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
1379
1400
fn fold_impl_item ( & mut self , item : ast:: ImplItem ) -> OneVector < ast:: ImplItem > {
1380
1401
let item = configure ! ( self , item) ;
1381
1402
1382
- let ( attr, traits, item) = self . classify_item ( item) ;
1403
+ let ( attr, traits, item, together_with ) = self . classify_item ( item) ;
1383
1404
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 ( ) ;
1387
1407
}
1388
1408
1389
1409
match item. node {
@@ -1414,12 +1434,12 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
1414
1434
1415
1435
fn fold_foreign_item ( & mut self ,
1416
1436
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) ;
1418
1438
1419
1439
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 ( ) ;
1423
1443
}
1424
1444
1425
1445
if let ast:: ForeignItemKind :: Macro ( mac) = foreign_item. node {
0 commit comments