@@ -279,9 +279,9 @@ impl<'a> Parser<'a> {
279279 } else if self . eat_keyword ( kw:: Macro ) {
280280 // MACROS 2.0 ITEM
281281 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 ( ) {
283283 // MACRO_RULES ITEM
284- self . parse_item_macro_rules ( vis) ?
284+ self . parse_item_macro_rules ( vis, has_bang ) ?
285285 } else if vis. kind . is_pub ( ) && self . isnt_macro_invocation ( ) {
286286 self . recover_missing_kw_before_item ( ) ?;
287287 return Ok ( None ) ;
@@ -300,7 +300,7 @@ impl<'a> Parser<'a> {
300300 || self . is_kw_followed_by_ident ( kw:: Union ) // no: `union::b`, yes: `union U { .. }`
301301 || self . check_auto_or_unsafe_trait_item ( ) // no: `auto::b`, yes: `auto trait X { .. }`
302302 || 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`
304304 }
305305
306306 /// Are we sure this could not possibly be a macro invocation?
@@ -1534,18 +1534,43 @@ impl<'a> Parser<'a> {
15341534 Ok ( ( ident, ItemKind :: MacroDef ( ast:: MacroDef { body, macro_rules : false } ) ) )
15351535 }
15361536
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
15421561 }
15431562
15441563 /// 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 > {
15461569 self . expect_keyword ( kw:: MacroRules ) ?; // `macro_rules`
1547- self . expect ( & token:: Not ) ?; // `!`
15481570
1571+ if has_bang {
1572+ self . expect ( & token:: Not ) ?; // `!`
1573+ }
15491574 let ident = self . parse_ident ( ) ?;
15501575
15511576 if self . eat ( & token:: Not ) {
@@ -2121,3 +2146,8 @@ impl<'a> Parser<'a> {
21212146 }
21222147 }
21232148}
2149+
2150+ enum IsMacroRulesItem {
2151+ Yes { has_bang : bool } ,
2152+ No ,
2153+ }
0 commit comments