@@ -279,9 +279,9 @@ impl<'a> Parser<'a> {
279
279
} else if self . eat_keyword ( kw:: Macro ) {
280
280
// MACROS 2.0 ITEM
281
281
self . parse_item_decl_macro ( lo) ?
282
- } else if self . is_macro_rules_item ( ) {
282
+ } else if let IsMacroRulesItem :: Yes { has_bang } = self . is_macro_rules_item ( ) {
283
283
// MACRO_RULES ITEM
284
- self . parse_item_macro_rules ( vis) ?
284
+ self . parse_item_macro_rules ( vis, has_bang ) ?
285
285
} else if vis. kind . is_pub ( ) && self . isnt_macro_invocation ( ) {
286
286
self . recover_missing_kw_before_item ( ) ?;
287
287
return Ok ( None ) ;
@@ -300,7 +300,7 @@ impl<'a> Parser<'a> {
300
300
|| self . is_kw_followed_by_ident ( kw:: Union ) // no: `union::b`, yes: `union U { .. }`
301
301
|| self . check_auto_or_unsafe_trait_item ( ) // no: `auto::b`, yes: `auto trait X { .. }`
302
302
|| self . is_async_fn ( ) // no(2015): `async::b`, yes: `async fn`
303
- || self . is_macro_rules_item ( ) // no: `macro_rules::b`, yes: `macro_rules! mac`
303
+ || matches ! ( self . is_macro_rules_item( ) , IsMacroRulesItem :: Yes { .. } ) // no: `macro_rules::b`, yes: `macro_rules! mac`
304
304
}
305
305
306
306
/// Are we sure this could not possibly be a macro invocation?
@@ -1534,18 +1534,43 @@ impl<'a> Parser<'a> {
1534
1534
Ok ( ( ident, ItemKind :: MacroDef ( ast:: MacroDef { body, macro_rules : false } ) ) )
1535
1535
}
1536
1536
1537
- /// Is this unambiguously the start of a `macro_rules! foo` item definition?
1538
- fn is_macro_rules_item ( & mut self ) -> bool {
1539
- self . check_keyword ( kw:: MacroRules )
1540
- && self . look_ahead ( 1 , |t| * t == token:: Not )
1541
- && self . look_ahead ( 2 , |t| t. is_ident ( ) )
1537
+ /// Is this a possibly malformed start of a `macro_rules! foo` item definition?
1538
+
1539
+ fn is_macro_rules_item ( & mut self ) -> IsMacroRulesItem {
1540
+ if self . check_keyword ( kw:: MacroRules ) {
1541
+ let macro_rules_span = self . token . span ;
1542
+
1543
+ if self . look_ahead ( 1 , |t| * t == token:: Not ) && self . look_ahead ( 2 , |t| t. is_ident ( ) ) {
1544
+ return IsMacroRulesItem :: Yes { has_bang : true } ;
1545
+ } else if self . look_ahead ( 1 , |t| ( t. is_ident ( ) ) ) {
1546
+ // macro_rules foo
1547
+ self . struct_span_err ( macro_rules_span, "expected `!` after `macro_rules`" )
1548
+ . span_suggestion (
1549
+ macro_rules_span,
1550
+ "add a `!`" ,
1551
+ "macro_rules!" . to_owned ( ) ,
1552
+ Applicability :: MachineApplicable ,
1553
+ )
1554
+ . emit ( ) ;
1555
+
1556
+ return IsMacroRulesItem :: Yes { has_bang : false } ;
1557
+ }
1558
+ }
1559
+
1560
+ IsMacroRulesItem :: No
1542
1561
}
1543
1562
1544
1563
/// Parses a `macro_rules! foo { ... }` declarative macro.
1545
- fn parse_item_macro_rules ( & mut self , vis : & Visibility ) -> PResult < ' a , ItemInfo > {
1564
+ fn parse_item_macro_rules (
1565
+ & mut self ,
1566
+ vis : & Visibility ,
1567
+ has_bang : bool ,
1568
+ ) -> PResult < ' a , ItemInfo > {
1546
1569
self . expect_keyword ( kw:: MacroRules ) ?; // `macro_rules`
1547
- self . expect ( & token:: Not ) ?; // `!`
1548
1570
1571
+ if has_bang {
1572
+ self . expect ( & token:: Not ) ?; // `!`
1573
+ }
1549
1574
let ident = self . parse_ident ( ) ?;
1550
1575
1551
1576
if self . eat ( & token:: Not ) {
@@ -2121,3 +2146,8 @@ impl<'a> Parser<'a> {
2121
2146
}
2122
2147
}
2123
2148
}
2149
+
2150
+ enum IsMacroRulesItem {
2151
+ Yes { has_bang : bool } ,
2152
+ No ,
2153
+ }
0 commit comments