Rollup merge of #150590 - ident-kw-ice, r=petrochenkov

Don't try to recover keyword as non-keyword identifier

Fixes rust-lang/rust#149692.

On beta after rust-lang/rust#146978, we ICE on

```rs
macro_rules! m {
    ($id:item()) => {}
}

m!(Self());
```

where `Self` in the macro invocation is a keyword not a "normal" identifier, while attempting to recover an missing keyword before an identifier. Except, `Self` *is* a keyword, so trying to parse that as a non-reserved identifier expectedly fails.

I suspect rust-lang/rust#146978 merely unmasked a possible code path to hit this case; this logic has been so for a good while. Previously, on stable, the error message looks something like

```rs
error: expected identifier, found keyword `Self`
 --> src/lib.rs:5:4
  |
5 | m!(Self());
  |    ^^^^ expected identifier, found keyword

error: missing `fn` or `struct` for function or struct definition
 --> src/lib.rs:5:4
  |
2 |     ($id:item()) => {}
  |      -------- while parsing argument for this `item` macro fragment
...
5 | m!(Self());
  |    ^^^^
  |
help: if you meant to call a macro, try
  |
5 | m!(Self!());
  |        +
```

I considered restoring this diagnostic, but I'm not super convinced it's worth the complexity (and to me, it's not super clear what the user actually intended here).
This commit is contained in:
Jonathan Brouwer 2026-01-14 22:29:56 +01:00 committed by GitHub
commit 9ef76797ea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 71 additions and 0 deletions

View file

@ -408,6 +408,7 @@ impl<'a> Parser<'a> {
let insert_span = ident_span.shrink_to_lo();
let ident = if self.token.is_ident()
&& self.token.is_non_reserved_ident()
&& (!is_const || self.look_ahead(1, |t| *t == token::OpenParen))
&& self.look_ahead(1, |t| {
matches!(t.kind, token::Lt | token::OpenBrace | token::OpenParen)

View file

@ -0,0 +1,11 @@
//! More test coverage for <https://github.com/rust-lang/rust/issues/149692>; this test is
//! specifically for `const` items.
macro_rules! m {
(const $id:item()) => {}
}
m!(const Self());
//~^ ERROR expected one of `!` or `::`, found `(`
fn main() {}

View file

@ -0,0 +1,11 @@
error: expected one of `!` or `::`, found `(`
--> $DIR/kw-in-const-item-pos-recovery-149692.rs:8:14
|
LL | (const $id:item()) => {}
| -------- while parsing argument for this `item` macro fragment
...
LL | m!(const Self());
| ^ expected one of `!` or `::`
error: aborting due to 1 previous error

View file

@ -0,0 +1,19 @@
//! Regression test for a diagnostic ICE where we tried to recover a keyword as the identifier when
//! we are already trying to recover a missing keyword before item.
//!
//! See <https://github.com/rust-lang/rust/issues/149692>.
macro_rules! m {
($id:item()) => {}
}
m!(Self());
//~^ ERROR expected one of `!` or `::`, found `(`
m!(Self{});
//~^ ERROR expected one of `!` or `::`, found `{`
m!(crate());
//~^ ERROR expected one of `!` or `::`, found `(`
fn main() {}

View file

@ -0,0 +1,29 @@
error: expected one of `!` or `::`, found `(`
--> $DIR/kw-in-item-pos-recovery-149692.rs:10:8
|
LL | ($id:item()) => {}
| -------- while parsing argument for this `item` macro fragment
...
LL | m!(Self());
| ^ expected one of `!` or `::`
error: expected one of `!` or `::`, found `{`
--> $DIR/kw-in-item-pos-recovery-149692.rs:13:8
|
LL | ($id:item()) => {}
| -------- while parsing argument for this `item` macro fragment
...
LL | m!(Self{});
| ^ expected one of `!` or `::`
error: expected one of `!` or `::`, found `(`
--> $DIR/kw-in-item-pos-recovery-149692.rs:16:9
|
LL | ($id:item()) => {}
| -------- while parsing argument for this `item` macro fragment
...
LL | m!(crate());
| ^ expected one of `!` or `::`
error: aborting due to 3 previous errors