Skip to content

Commit

Permalink
Rollup merge of #89257 - aDotInTheVoid:macro-error-2, r=estebank
Browse files Browse the repository at this point in the history
Give better error for `macro_rules name`

follow up to #89221

r? ``@estebank``

``@rustbot`` modify labels: +A-diagnostics +A-parser
  • Loading branch information
JohnTitor committed Oct 22, 2021
2 parents 918f9cc + 729ff2d commit 8738d5d
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 10 deletions.
50 changes: 40 additions & 10 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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?
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -2121,3 +2146,8 @@ impl<'a> Parser<'a> {
}
}
}

enum IsMacroRulesItem {
Yes { has_bang: bool },
No,
}
16 changes: 16 additions & 0 deletions src/test/ui/macros/missing-bang-in-decl.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// run-rustfix

#![allow(unused_macros)]

macro_rules! foo {
//~^ ERROR expected `!` after `macro_rules`
() => {};
}

macro_rules! bar {
//~^ ERROR expected `!` after `macro_rules`
//~^^ ERROR macro names aren't followed by a `!`
() => {};
}

fn main() {}
16 changes: 16 additions & 0 deletions src/test/ui/macros/missing-bang-in-decl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// run-rustfix

#![allow(unused_macros)]

macro_rules foo {
//~^ ERROR expected `!` after `macro_rules`
() => {};
}

macro_rules bar! {
//~^ ERROR expected `!` after `macro_rules`
//~^^ ERROR macro names aren't followed by a `!`
() => {};
}

fn main() {}
20 changes: 20 additions & 0 deletions src/test/ui/macros/missing-bang-in-decl.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error: expected `!` after `macro_rules`
--> $DIR/missing-bang-in-decl.rs:5:1
|
LL | macro_rules foo {
| ^^^^^^^^^^^ help: add a `!`: `macro_rules!`

error: expected `!` after `macro_rules`
--> $DIR/missing-bang-in-decl.rs:10:1
|
LL | macro_rules bar! {
| ^^^^^^^^^^^ help: add a `!`: `macro_rules!`

error: macro names aren't followed by a `!`
--> $DIR/missing-bang-in-decl.rs:10:16
|
LL | macro_rules bar! {
| ^ help: remove the `!`

error: aborting due to 3 previous errors

0 comments on commit 8738d5d

Please sign in to comment.