Skip to content

Commit 8738d5d

Browse files
authored
Rollup merge of #89257 - aDotInTheVoid:macro-error-2, r=estebank
Give better error for `macro_rules name` follow up to #89221 r? ``@estebank`` ``@rustbot`` modify labels: +A-diagnostics +A-parser
2 parents 918f9cc + 729ff2d commit 8738d5d

File tree

4 files changed

+92
-10
lines changed

4 files changed

+92
-10
lines changed

compiler/rustc_parse/src/parser/item.rs

+40-10
Original file line numberDiff line numberDiff line change
@@ -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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// run-rustfix
2+
3+
#![allow(unused_macros)]
4+
5+
macro_rules! foo {
6+
//~^ ERROR expected `!` after `macro_rules`
7+
() => {};
8+
}
9+
10+
macro_rules! bar {
11+
//~^ ERROR expected `!` after `macro_rules`
12+
//~^^ ERROR macro names aren't followed by a `!`
13+
() => {};
14+
}
15+
16+
fn main() {}
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// run-rustfix
2+
3+
#![allow(unused_macros)]
4+
5+
macro_rules foo {
6+
//~^ ERROR expected `!` after `macro_rules`
7+
() => {};
8+
}
9+
10+
macro_rules bar! {
11+
//~^ ERROR expected `!` after `macro_rules`
12+
//~^^ ERROR macro names aren't followed by a `!`
13+
() => {};
14+
}
15+
16+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: expected `!` after `macro_rules`
2+
--> $DIR/missing-bang-in-decl.rs:5:1
3+
|
4+
LL | macro_rules foo {
5+
| ^^^^^^^^^^^ help: add a `!`: `macro_rules!`
6+
7+
error: expected `!` after `macro_rules`
8+
--> $DIR/missing-bang-in-decl.rs:10:1
9+
|
10+
LL | macro_rules bar! {
11+
| ^^^^^^^^^^^ help: add a `!`: `macro_rules!`
12+
13+
error: macro names aren't followed by a `!`
14+
--> $DIR/missing-bang-in-decl.rs:10:16
15+
|
16+
LL | macro_rules bar! {
17+
| ^ help: remove the `!`
18+
19+
error: aborting due to 3 previous errors
20+

0 commit comments

Comments
 (0)