@@ -12,7 +12,7 @@ use rustc_ast::ptr::P;
12
12
use rustc_ast:: token;
13
13
use rustc_ast:: tokenstream:: TokenStream ;
14
14
use rustc_ast:: visit:: { self , AssocCtxt , Visitor } ;
15
- use rustc_ast:: { AstLike , Block , Inline , ItemKind , Local , MacArgs , MacCall } ;
15
+ use rustc_ast:: { AstLike , Block , Inline , ItemKind , MacArgs , MacCall } ;
16
16
use rustc_ast:: { MacCallStmt , MacStmtStyle , MetaItemKind , ModKind , NestedMetaItem } ;
17
17
use rustc_ast:: { NodeId , PatKind , Path , StmtKind , Unsafe } ;
18
18
use rustc_ast_pretty:: pprust;
@@ -559,7 +559,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
559
559
self . cx . force_mode = orig_force_mode;
560
560
561
561
// Finally incorporate all the expanded macros into the input AST fragment.
562
- let mut placeholder_expander = PlaceholderExpander :: new ( self . cx , self . monotonic ) ;
562
+ let mut placeholder_expander = PlaceholderExpander :: default ( ) ;
563
563
while let Some ( expanded_fragments) = expanded_fragments. pop ( ) {
564
564
for ( expn_id, expanded_fragment) in expanded_fragments. into_iter ( ) . rev ( ) {
565
565
placeholder_expander
@@ -1061,13 +1061,51 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
1061
1061
attr
1062
1062
}
1063
1063
1064
+ fn take_stmt_bang (
1065
+ & mut self ,
1066
+ stmt : ast:: Stmt ,
1067
+ ) -> Result < ( bool , MacCall , Vec < ast:: Attribute > ) , ast:: Stmt > {
1068
+ match stmt. kind {
1069
+ StmtKind :: MacCall ( mac) => {
1070
+ let MacCallStmt { mac, style, attrs, .. } = mac. into_inner ( ) ;
1071
+ Ok ( ( style == MacStmtStyle :: Semicolon , mac, attrs. into ( ) ) )
1072
+ }
1073
+ StmtKind :: Item ( ref item) if matches ! ( item. kind, ItemKind :: MacCall ( ..) ) => {
1074
+ match stmt. kind {
1075
+ StmtKind :: Item ( item) => match item. into_inner ( ) {
1076
+ ast:: Item { kind : ItemKind :: MacCall ( mac) , attrs, .. } => {
1077
+ Ok ( ( mac. args . need_semicolon ( ) , mac, attrs) )
1078
+ }
1079
+ _ => unreachable ! ( ) ,
1080
+ } ,
1081
+ _ => unreachable ! ( ) ,
1082
+ }
1083
+ }
1084
+ StmtKind :: Semi ( ref expr) if matches ! ( expr. kind, ast:: ExprKind :: MacCall ( ..) ) => {
1085
+ match stmt. kind {
1086
+ StmtKind :: Semi ( expr) => match expr. into_inner ( ) {
1087
+ ast:: Expr { kind : ast:: ExprKind :: MacCall ( mac) , attrs, .. } => {
1088
+ Ok ( ( mac. args . need_semicolon ( ) , mac, attrs. into ( ) ) )
1089
+ }
1090
+ _ => unreachable ! ( ) ,
1091
+ } ,
1092
+ _ => unreachable ! ( ) ,
1093
+ }
1094
+ }
1095
+ StmtKind :: Local ( ..) | StmtKind :: Empty | StmtKind :: Item ( ..) | StmtKind :: Semi ( ..) => {
1096
+ Err ( stmt)
1097
+ }
1098
+ StmtKind :: Expr ( ..) => unreachable ! ( ) ,
1099
+ }
1100
+ }
1101
+
1064
1102
fn configure < T : AstLike > ( & mut self , node : T ) -> Option < T > {
1065
1103
self . cfg . configure ( node)
1066
1104
}
1067
1105
1068
1106
// Detect use of feature-gated or invalid attributes on macro invocations
1069
1107
// since they will not be detected after macro expansion.
1070
- fn check_attributes ( & mut self , attrs : & [ ast:: Attribute ] , call : & MacCall ) {
1108
+ fn check_attributes ( & self , attrs : & [ ast:: Attribute ] , call : & MacCall ) {
1071
1109
let features = self . cx . ecfg . features . unwrap ( ) ;
1072
1110
let mut attrs = attrs. iter ( ) . peekable ( ) ;
1073
1111
let mut span: Option < Span > = None ;
@@ -1177,11 +1215,6 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
1177
1215
} ) ;
1178
1216
}
1179
1217
1180
- // This is needed in order to set `lint_node_id` for `let` statements
1181
- fn visit_local ( & mut self , local : & mut P < Local > ) {
1182
- assign_id ! ( self , & mut local. id, || noop_visit_local( local, self ) ) ;
1183
- }
1184
-
1185
1218
fn flat_map_arm ( & mut self , arm : ast:: Arm ) -> SmallVec < [ ast:: Arm ; 1 ] > {
1186
1219
let mut arm = configure ! ( self , arm) ;
1187
1220
@@ -1299,31 +1332,39 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
1299
1332
fn flat_map_stmt ( & mut self , stmt : ast:: Stmt ) -> SmallVec < [ ast:: Stmt ; 1 ] > {
1300
1333
let mut stmt = configure ! ( self , stmt) ;
1301
1334
1302
- // we'll expand attributes on expressions separately
1303
- if !stmt. is_expr ( ) {
1335
+ // We pull macro invocations (both attributes and fn-like macro calls) out of their
1336
+ // `StmtKind`s and treat them as statement macro invocations, not as items or expressions.
1337
+ // FIXME: invocations in semicolon-less expressions positions are expanded as expressions,
1338
+ // changing that requires some compatibility measures.
1339
+ let mut stmt = if !stmt. is_expr ( ) {
1304
1340
if let Some ( attr) = self . take_first_attr ( & mut stmt) {
1305
1341
return self
1306
1342
. collect_attr ( attr, Annotatable :: Stmt ( P ( stmt) ) , AstFragmentKind :: Stmts )
1307
1343
. make_stmts ( ) ;
1308
1344
}
1309
- }
1310
1345
1311
- if let StmtKind :: MacCall ( mac) = stmt. kind {
1312
- let MacCallStmt { mac, style, attrs, tokens : _ } = mac. into_inner ( ) ;
1313
- self . check_attributes ( & attrs, & mac) ;
1314
- let mut placeholder =
1315
- self . collect_bang ( mac, stmt. span , AstFragmentKind :: Stmts ) . make_stmts ( ) ;
1316
-
1317
- // If this is a macro invocation with a semicolon, then apply that
1318
- // semicolon to the final statement produced by expansion.
1319
- if style == MacStmtStyle :: Semicolon {
1320
- if let Some ( stmt) = placeholder. pop ( ) {
1321
- placeholder. push ( stmt. add_trailing_semicolon ( ) ) ;
1346
+ let span = stmt. span ;
1347
+ match self . take_stmt_bang ( stmt) {
1348
+ Ok ( ( add_semicolon, mac, attrs) ) => {
1349
+ self . check_attributes ( & attrs, & mac) ;
1350
+ let mut stmts =
1351
+ self . collect_bang ( mac, span, AstFragmentKind :: Stmts ) . make_stmts ( ) ;
1352
+
1353
+ // If this is a macro invocation with a semicolon, then apply that
1354
+ // semicolon to the final statement produced by expansion.
1355
+ if add_semicolon {
1356
+ if let Some ( stmt) = stmts. pop ( ) {
1357
+ stmts. push ( stmt. add_trailing_semicolon ( ) ) ;
1358
+ }
1359
+ }
1360
+
1361
+ return stmts;
1322
1362
}
1363
+ Err ( stmt) => stmt,
1323
1364
}
1324
-
1325
- return placeholder ;
1326
- }
1365
+ } else {
1366
+ stmt
1367
+ } ;
1327
1368
1328
1369
// The only way that we can end up with a `MacCall` expression statement,
1329
1370
// (as opposed to a `StmtKind::MacCall`) is if we have a macro as the
@@ -1338,14 +1379,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
1338
1379
}
1339
1380
}
1340
1381
1341
- // The placeholder expander gives ids to statements, so we avoid folding the id here.
1342
- // We don't use `assign_id!` - it will be called when we visit statement's contents
1343
- // (e.g. an expression, item, or local)
1344
- let ast:: Stmt { id, kind, span } = stmt;
1345
- let res = noop_flat_map_stmt_kind ( kind, self )
1346
- . into_iter ( )
1347
- . map ( |kind| ast:: Stmt { id, kind, span } )
1348
- . collect ( ) ;
1382
+ let res = assign_id ! ( self , & mut stmt. id, || noop_flat_map_stmt( stmt, self ) ) ;
1349
1383
1350
1384
self . cx . current_expansion . is_trailing_mac = false ;
1351
1385
res
0 commit comments