about summary refs log tree commit diff
path: root/compiler/rustc_parse/src/parser
diff options
context:
space:
mode:
authorNixon Enraght-Moony <nixon.emoony@gmail.com>2021-09-25 20:51:46 +0100
committerNixon Enraght-Moony <nixon.emoony@gmail.com>2021-10-01 22:47:39 +0100
commit729ff2d00653feec9810857a7a6b06559d78cfb8 (patch)
tree3984e37db88095ff36d3070e54620f68ed56dae3 /compiler/rustc_parse/src/parser
parent63cc2bb3d07d6c726dfcdc5f95cbe5ed4760641a (diff)
downloadrust-729ff2d00653feec9810857a7a6b06559d78cfb8.tar.gz
rust-729ff2d00653feec9810857a7a6b06559d78cfb8.zip
Give better error for `macro_rules name`
Diffstat (limited to 'compiler/rustc_parse/src/parser')
-rw-r--r--compiler/rustc_parse/src/parser/item.rs50
1 files changed, 40 insertions, 10 deletions
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 624390a406f..c436e82d974 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -279,9 +279,9 @@ impl<'a> Parser<'a> {
         } else if self.eat_keyword(kw::Macro) {
             // MACROS 2.0 ITEM
             self.parse_item_decl_macro(lo)?
-        } else if self.is_macro_rules_item() {
+        } else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() {
             // MACRO_RULES ITEM
-            self.parse_item_macro_rules(vis)?
+            self.parse_item_macro_rules(vis, has_bang)?
         } else if vis.kind.is_pub() && self.isnt_macro_invocation() {
             self.recover_missing_kw_before_item()?;
             return Ok(None);
@@ -300,7 +300,7 @@ impl<'a> Parser<'a> {
         || self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`
         || self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }`
         || self.is_async_fn() // no(2015): `async::b`, yes: `async fn`
-        || self.is_macro_rules_item() // no: `macro_rules::b`, yes: `macro_rules! mac`
+        || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac`
     }
 
     /// Are we sure this could not possibly be a macro invocation?
@@ -1534,18 +1534,43 @@ impl<'a> Parser<'a> {
         Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, macro_rules: false })))
     }
 
-    /// Is this unambiguously the start of a `macro_rules! foo` item definition?
-    fn is_macro_rules_item(&mut self) -> bool {
-        self.check_keyword(kw::MacroRules)
-            && self.look_ahead(1, |t| *t == token::Not)
-            && self.look_ahead(2, |t| t.is_ident())
+    /// Is this a possibly malformed start of a `macro_rules! foo` item definition?
+
+    fn is_macro_rules_item(&mut self) -> IsMacroRulesItem {
+        if self.check_keyword(kw::MacroRules) {
+            let macro_rules_span = self.token.span;
+
+            if self.look_ahead(1, |t| *t == token::Not) && self.look_ahead(2, |t| t.is_ident()) {
+                return IsMacroRulesItem::Yes { has_bang: true };
+            } else if self.look_ahead(1, |t| (t.is_ident())) {
+                // macro_rules foo
+                self.struct_span_err(macro_rules_span, "expected `!` after `macro_rules`")
+                    .span_suggestion(
+                        macro_rules_span,
+                        "add a `!`",
+                        "macro_rules!".to_owned(),
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+
+                return IsMacroRulesItem::Yes { has_bang: false };
+            }
+        }
+
+        IsMacroRulesItem::No
     }
 
     /// Parses a `macro_rules! foo { ... }` declarative macro.
-    fn parse_item_macro_rules(&mut self, vis: &Visibility) -> PResult<'a, ItemInfo> {
+    fn parse_item_macro_rules(
+        &mut self,
+        vis: &Visibility,
+        has_bang: bool,
+    ) -> PResult<'a, ItemInfo> {
         self.expect_keyword(kw::MacroRules)?; // `macro_rules`
-        self.expect(&token::Not)?; // `!`
 
+        if has_bang {
+            self.expect(&token::Not)?; // `!`
+        }
         let ident = self.parse_ident()?;
 
         if self.eat(&token::Not) {
@@ -2121,3 +2146,8 @@ impl<'a> Parser<'a> {
         }
     }
 }
+
+enum IsMacroRulesItem {
+    Yes { has_bang: bool },
+    No,
+}