rust-lang / rust-lang/rust

`let-else` does not respect `macro_rules` `expr` metavariable grouping

Open
#147,899 4 comments 0 reactions 1 assignee View on GitHub

@bb1yd is already working on this.

Since Jun 28, 2026.

A-macros A-parser C-bug T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

Code 1: let-else with &&

macro_rules! foo {
    ($e:expr) => {
        let true = $e else { return; };
    }
}

fn main() {
    foo!(true && true);
}
error: a `&&` expression cannot be directly assigned in `let...else`
 --> src/main.rs:8:10
  |
8 |     foo!(true && true);
  |          ^^^^^^^^^^^^
  |
help: wrap the expression in parentheses
  |
8 |     foo!((true && true));
  |          +            +

Code 2: let-else with braces

#![allow(irrefutable_let_patterns)]

macro_rules! foo {
    ($e:expr) => {
        let _ = $e else { return; };
    }
}

struct Thing {}

fn main() {
    foo!(Thing {});
}
error: right curly brace `}` before `else` in a `let...else` statement not allowed
  --> src/main.rs:12:17
   |
12 |     foo!(Thing {});
   |                 ^
   |
help: wrap the expression in parentheses
   |
12 |     foo!((Thing {}));
   |          +        +

I expected both of the above code snippets to compile. Instead, I got the above compile errors.

expr metavariables in macros are supposed to be opaque, and treated as if they're wrapped in "invisible parentheses". Therefore, I shouldn't need to wrap the expression in another layer of parentheses. However, let-else seems to not respect this grouping.

In contrast, if let correctly respects the grouping

if let with &&

This code correctly prints "works" three times.

macro_rules! foo {
    ($e:expr) => {
        if let false = $e {
            println!("works");
        } else {
            unreachable!();
        }
    }
}

fn main() {
    foo!(true && false);
    if let false = (true && false) {
        println!("works");
    } else {
        unreachable!();
    }
    if let false = true && false {
        unreachable!();
    } else {
        println!("works");
    }
}
if let with braces

This code compiles

#![allow(irrefutable_let_patterns)]

macro_rules! foo {
    ($e:expr) => {
        if let _ = $e {}
    }
}

struct Thing {}

fn main() {
    foo!(Thing {});
}
Meta

Reproducible on the playground with version 1.92.0-nightly (2025-10-19 f04e3dfc87d7e2b6ad53)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.