Skip to content

macro parses let keyword as pattern and fails + masked regression #109045

Open
@Ezrashaw

Description

@Ezrashaw

I tried this code:

macro_rules! let_let_oof {
    ($p:pat) => {
        let_let_oof! { let let $p }
    };
    (let let $p:pat) => {
        fn a() {
           let $p = 5; 
        } 
    }
}

let_let_oof! { x }

I expected the code to compile and the macro to expand as follows:

fn a() {
  let x = 5;
}

Instead, compilation failed:

error: expected pattern, found `let`
  --> bad-code2.rs:3:24
   |
3  |         let_let_oof! { let let $p }
   |                        ^^^ help: remove the unnecessary `let` keyword
...
12 | let_let_oof! { x }
   | ------------------ in this macro invocation
   |
   = note: this error originates in the macro `let_let_oof` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected identifier, found keyword `let`
  --> bad-code2.rs:3:28
   |
3  |         let_let_oof! { let let $p }
   |                            ^^^ expected identifier, found keyword
...
12 | let_let_oof! { x }
   | ------------------ in this macro invocation
   |
   = note: this error originates in the macro `let_let_oof` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 2 previous errors

Meta

rustc --version --verbose:

rustc 1.70.0-nightly (8a73f50d8 2023-03-11)
binary: rustc
commit-hash: 8a73f50d875840b8077b8ec080fa41881d7ce40d
commit-date: 2023-03-11
host: x86_64-unknown-linux-gnu
release: 1.70.0-nightly
LLVM version: 15.0.7

Occurs on latest stable and nightly.

Additional context

I believe there are two issues here:

  1. (error 2) The parser consumes let as an identifier and then fails because it is not a valid identifier; Parser::can_be_ident_pat (see compiler/rustc_parse/parser/pat.rs:811) returns true on keywords and then the caller (compiler/rustc_parse/parser/pat.rs:398) attempts to parse an ident pattern and promptly fails because it sees a keyword.
  2. (error 1) On top of this (and thus no code has been broken), a regression occurred with the introduction of the following code (see compiler/rustc_parse/parser/pat.rs:345) which eagerly consumes tokens without being behind a Parser::may_recover gate (this is similar to Breaking change in macro_rules ty fragment parsing in version 1.68 #107796, that regression I caused, right? cc @compiler-errors):
if self.token.is_keyword(kw::Let) && self.look_ahead(1, |tok| tok.can_begin_pattern()) {
    self.bump();
    self.sess.emit_err(RemoveLet { span: lo });
    lo = self.token.span;
}

If this is correct, I'd like to PR it please :).

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)C-bugCategory: This is a bug.P-lowLow priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions