Skip to content

Commit 4c4b155

Browse files
committed
fix: better error cases with bad/missing identifiers in MBEs
1 parent f9d52dc commit 4c4b155

16 files changed

+130
-98
lines changed

compiler/rustc_parse/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,8 @@ parse_macro_name_remove_bang = macro names aren't followed by a `!`
468468
parse_macro_rules_missing_bang = expected `!` after `macro_rules`
469469
.suggestion = add a `!`
470470
471+
parse_macro_rules_named_macro_rules = user-defined macros may not be named `macro_rules`
472+
471473
parse_macro_rules_visibility = can't qualify macro_rules invocation with `{$vis}`
472474
.suggestion = try exporting the macro
473475
@@ -497,6 +499,8 @@ parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of
497499
498500
parse_maybe_missing_let = you might have meant to continue the let-chain
499501
502+
parse_maybe_missing_macro_rules_name = maybe you have forgotten to define a name for this `macro_rules!`
503+
500504
parse_maybe_recover_from_bad_qpath_stage_2 =
501505
missing angle brackets in associated item path
502506
.suggestion = types that don't start with an identifier need to be surrounded with angle brackets in qualified paths

compiler/rustc_parse/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -2664,6 +2664,13 @@ pub(crate) struct MacroRulesMissingBang {
26642664
pub hi: Span,
26652665
}
26662666

2667+
#[derive(Diagnostic)]
2668+
#[diag(parse_macro_rules_named_macro_rules)]
2669+
pub(crate) struct MacroRulesNamedMacroRules {
2670+
#[primary_span]
2671+
pub span: Span,
2672+
}
2673+
26672674
#[derive(Diagnostic)]
26682675
#[diag(parse_macro_name_remove_bang)]
26692676
pub(crate) struct MacroNameRemoveBang {

compiler/rustc_parse/src/parser/item.rs

+52-14
Original file line numberDiff line numberDiff line change
@@ -2036,23 +2036,26 @@ impl<'a> Parser<'a> {
20362036

20372037
/// Is this a possibly malformed start of a `macro_rules! foo` item definition?
20382038
fn is_macro_rules_item(&mut self) -> IsMacroRulesItem {
2039-
if self.check_keyword(kw::MacroRules) {
2040-
let macro_rules_span = self.token.span;
2041-
2042-
if self.look_ahead(1, |t| *t == token::Not) && self.look_ahead(2, |t| t.is_ident()) {
2043-
return IsMacroRulesItem::Yes { has_bang: true };
2044-
} else if self.look_ahead(1, |t| (t.is_ident())) {
2045-
// macro_rules foo
2046-
self.sess.emit_err(errors::MacroRulesMissingBang {
2047-
span: macro_rules_span,
2048-
hi: macro_rules_span.shrink_to_hi(),
2049-
});
2039+
if !self.check_keyword(kw::MacroRules) {
2040+
return IsMacroRulesItem::No;
2041+
}
2042+
2043+
let macro_rules_span = self.token.span;
2044+
let has_bang = self.look_ahead(1, |t| *t == token::Not);
20502045

2051-
return IsMacroRulesItem::Yes { has_bang: false };
2046+
// macro_rules foo
2047+
if !has_bang {
2048+
if !self.look_ahead(1, |t| (t.is_ident())) {
2049+
return IsMacroRulesItem::No;
20522050
}
2051+
2052+
self.sess.emit_err(errors::MacroRulesMissingBang {
2053+
span: macro_rules_span,
2054+
hi: macro_rules_span.shrink_to_hi(),
2055+
});
20532056
}
20542057

2055-
IsMacroRulesItem::No
2058+
IsMacroRulesItem::Yes { has_bang }
20562059
}
20572060

20582061
/// Parses a `macro_rules! foo { ... }` declarative macro.
@@ -2066,7 +2069,42 @@ impl<'a> Parser<'a> {
20662069
if has_bang {
20672070
self.expect(&token::Not)?; // `!`
20682071
}
2069-
let ident = self.parse_ident()?;
2072+
2073+
let ident = match self.parse_ident() {
2074+
Ok(ident) => ident,
2075+
Err(mut err) => {
2076+
match (
2077+
&self.token.kind,
2078+
self.look_ahead(1, |token| token.ident()),
2079+
self.look_ahead(2, |token| {
2080+
(token.kind == TokenKind::CloseDelim(Delimiter::Parenthesis))
2081+
.then_some(token.span)
2082+
}),
2083+
) {
2084+
(
2085+
TokenKind::OpenDelim(Delimiter::Parenthesis),
2086+
Some((Ident { name, .. }, _)),
2087+
Some(closing_span),
2088+
) => {
2089+
err.span_suggestion(
2090+
self.token.span.with_hi(closing_span.hi()),
2091+
"try removing the parenthesis around the name for this `macro_rules!`",
2092+
name,
2093+
Applicability::MachineApplicable,
2094+
);
2095+
}
2096+
_ => {
2097+
err.help(fluent::parse_maybe_missing_macro_rules_name);
2098+
}
2099+
}
2100+
2101+
return Err(err);
2102+
}
2103+
};
2104+
2105+
if ident.name == sym::macro_rules {
2106+
self.sess.emit_err(errors::MacroRulesNamedMacroRules { span: ident.span });
2107+
}
20702108

20712109
if self.eat(&token::Not) {
20722110
// Handle macro_rules! foo!

compiler/rustc_resolve/messages.ftl

-2
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,6 @@ resolve_method_not_member_of_trait =
181181
method `{$method}` is not a member of trait `{$trait_}`
182182
.label = not a member of trait `{$trait_}`
183183
184-
resolve_missing_macro_rules_name = maybe you have forgotten to define a name for this `macro_rules!`
185-
186184
resolve_module_only =
187185
visibility must resolve to a module
188186

compiler/rustc_resolve/src/diagnostics.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use rustc_span::{BytePos, Span, SyntaxContext};
2828
use thin_vec::{thin_vec, ThinVec};
2929

3030
use crate::errors::{AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion};
31-
use crate::errors::{ConsiderAddingADerive, ExplicitUnsafeTraits, MaybeMissingMacroRulesName};
31+
use crate::errors::{ConsiderAddingADerive, ExplicitUnsafeTraits};
3232
use crate::imports::{Import, ImportKind};
3333
use crate::late::{PatternSource, Rib};
3434
use crate::path_names_to_string;
@@ -1419,11 +1419,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
14191419
"",
14201420
);
14211421

1422-
if macro_kind == MacroKind::Bang && ident.name == sym::macro_rules {
1423-
err.subdiagnostic(MaybeMissingMacroRulesName { span: ident.span });
1424-
return;
1425-
}
1426-
14271422
if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
14281423
err.subdiagnostic(ExplicitUnsafeTraits { span: ident.span, ident });
14291424
return;

compiler/rustc_resolve/src/errors.rs

-7
Original file line numberDiff line numberDiff line change
@@ -665,13 +665,6 @@ pub(crate) struct ExplicitUnsafeTraits {
665665
pub(crate) ident: Ident,
666666
}
667667

668-
#[derive(Subdiagnostic)]
669-
#[note(resolve_missing_macro_rules_name)]
670-
pub(crate) struct MaybeMissingMacroRulesName {
671-
#[primary_span]
672-
pub(crate) span: Span,
673-
}
674-
675668
#[derive(Subdiagnostic)]
676669
#[help(resolve_added_macro_use)]
677670
pub(crate) struct AddedMacroUse;

tests/ui/macros/issue-118786.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
macro_rules! make_macro {
66
($macro_name:tt) => {
77
macro_rules! $macro_name {
8-
//~^ ERROR macros that expand to items must be delimited with braces or followed by a semicolon
9-
//~| ERROR macro expansion ignores token `{` and any following
10-
//~| ERROR cannot find macro `macro_rules` in this scope
8+
//~^ ERROR: expected identifier, found `(`
119
() => {}
1210
}
1311
}

tests/ui/macros/issue-118786.stderr

+6-40
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,13 @@
1-
error: macros that expand to items must be delimited with braces or followed by a semicolon
1+
error: expected identifier, found `(`
22
--> $DIR/issue-118786.rs:7:22
33
|
44
LL | macro_rules! $macro_name {
5-
| ^^^^^^^^^^^
5+
| ^^^^^^^^^^^ expected identifier
66
|
7-
help: change the delimiters to curly braces
7+
help: try removing the parenthesis around the name for this `macro_rules!`
88
|
9-
LL | macro_rules! {} {
10-
| ~ +
11-
help: add a semicolon
12-
|
13-
LL | macro_rules! $macro_name; {
14-
| +
15-
16-
error: macro expansion ignores token `{` and any following
17-
--> $DIR/issue-118786.rs:7:34
18-
|
19-
LL | macro_rules! $macro_name {
20-
| ^
21-
...
22-
LL | make_macro!((meow));
23-
| ------------------- caused by the macro expansion here
24-
|
25-
= note: the usage of `make_macro!` is likely invalid in item context
26-
27-
error: cannot find macro `macro_rules` in this scope
28-
--> $DIR/issue-118786.rs:7:9
29-
|
30-
LL | macro_rules! $macro_name {
31-
| ^^^^^^^^^^^
32-
...
33-
LL | make_macro!((meow));
34-
| ------------------- in this macro invocation
35-
|
36-
note: maybe you have forgotten to define a name for this `macro_rules!`
37-
--> $DIR/issue-118786.rs:7:9
38-
|
39-
LL | macro_rules! $macro_name {
40-
| ^^^^^^^^^^^
41-
...
42-
LL | make_macro!((meow));
43-
| ------------------- in this macro invocation
44-
= note: this error originates in the macro `make_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
9+
LL | macro_rules! meow {
10+
| ~~~~
4511

46-
error: aborting due to 3 previous errors
12+
error: aborting due to 1 previous error
4713

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Ensures MBEs with a missing ident produce a readable error
2+
3+
macro_rules! {
4+
//~^ ERROR: expected identifier, found `{`
5+
//~| HELP: maybe you have forgotten to define a name for this `macro_rules!`
6+
() => {}
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: expected identifier, found `{`
2+
--> $DIR/mbe-missing-ident-error.rs:3:14
3+
|
4+
LL | macro_rules! {
5+
| ^ expected identifier
6+
|
7+
= help: maybe you have forgotten to define a name for this `macro_rules!`
8+
9+
error: aborting due to 1 previous error
10+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Ensures MBEs with a invalid ident produce a readable error
2+
3+
macro_rules! (meepmeep) {
4+
//~^ ERROR: expected identifier, found `(`
5+
//~| HELP: try removing the parenthesis around the name for this `macro_rules!`
6+
() => {}
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: expected identifier, found `(`
2+
--> $DIR/mbe-parenthesis-ident-error.rs:3:14
3+
|
4+
LL | macro_rules! (meepmeep) {
5+
| ^ expected identifier
6+
|
7+
help: try removing the parenthesis around the name for this `macro_rules!`
8+
|
9+
LL | macro_rules! meepmeep {
10+
| ~~~~~~~~
11+
12+
error: aborting due to 1 previous error
13+
+6-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
// check-pass
1+
// check-fail
22

3-
macro_rules! macro_rules { () => { struct S; } } // OK
3+
macro_rules! macro_rules { () => {} }
4+
//~^ ERROR: user-defined macros may not be named `macro_rules`
45

5-
macro_rules! {} // OK, calls the macro defined above
6-
7-
fn main() {
8-
let s = S;
9-
}
6+
macro_rules! {}
7+
//~^ ERROR: expected identifier, found `{`
8+
//~| HELP: maybe you have forgotten to define a name for this `macro_rules!`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: user-defined macros may not be named `macro_rules`
2+
--> $DIR/user-defined-macro-rules.rs:3:14
3+
|
4+
LL | macro_rules! macro_rules { () => {} }
5+
| ^^^^^^^^^^^
6+
7+
error: expected identifier, found `{`
8+
--> $DIR/user-defined-macro-rules.rs:6:14
9+
|
10+
LL | macro_rules! {}
11+
| ^ expected identifier
12+
|
13+
= help: maybe you have forgotten to define a name for this `macro_rules!`
14+
15+
error: aborting due to 2 previous errors
16+

tests/ui/resolve/issue-118295.rs

-5
This file was deleted.

tests/ui/resolve/issue-118295.stderr

-14
This file was deleted.

0 commit comments

Comments
 (0)