Skip to content

let and if let have different closure capture behaviors #153982

Description

@theemathas

I tried this code:

#![expect(dead_code, irrefutable_let_patterns)]

struct Thing(String, String);

fn foo(x: Thing) {
    let closure = || {
        if let Thing(_a, _) = x {}
    };
    println!("{}", size_of_val(&closure));
}

fn bar(x: Thing) {
    let closure = || {
        match x {
            Thing(_a, _) => {}
        }
    };
    println!("{}", size_of_val(&closure));
}

fn baz(x: Thing) {
    let closure = || {
        let Thing(_a, _) = x;
    };
    println!("{}", size_of_val(&closure));
}

fn main() {
    foo(Thing(String::from("a"), String::from("b")));
    bar(Thing(String::from("a"), String::from("b")));
    baz(Thing(String::from("a"), String::from("b")));
}

I expected the three printed numbers to be the same. Instead, in editions 2021 and 2024, the code prints 48 then 24 then 24.

It seems that if let causes the entire value of x to be captured, but let and match only capture the relevant field. This seems inconsistent.

cc @Nadrieril @meithecatte

Meta

Reproducible on the playground with version 1.96.0-nightly (2026-03-12 3102493c71626b5912d1) and also on version 1.94.0.

However, testing on Godbolt with version 1.93.0 (which is before #138961), it prints 48 then 48 then 24.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

A-closuresArea: Closures (`|…| { … }`)A-patternsRelating to patterns and pattern matchingC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions