Skip to content

unused_assignment triggered by closure even though value is used #141615

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
y86-dev opened this issue May 26, 2025 · 4 comments
Open

unused_assignment triggered by closure even though value is used #141615

y86-dev opened this issue May 26, 2025 · 4 comments
Labels
A-closures Area: Closures (`|…| { … }`) A-diagnostics Area: Messages for errors, warnings, and lints A-lints Area: Lints (warnings about flaws in source code) such as unused_mut. D-imprecise-spans Diagnostics: spans don't point to exactly the erroneous code L-unused_assignments Lint: unused_assignments T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@y86-dev
Copy link
Contributor

y86-dev commented May 26, 2025

Code

fn main() {
    let mut a: Option<u32> = None;
    let mut cl = move || {
        a = Some(42);
        a.take().unwrap()
    };
    println!("{}", cl())
}

Current output

warning: value captured by `a` is never read
 --> src/main.rs:4:9
  |
4 |         a = Some(42);
  |         ^
  |
  = help: did you mean to capture by reference instead?
  = note: `#[warn(unused_assignments)]` on by default

Desired output

warning: value assigned to `a` is never read
 --> src/main.rs:2:13
  |
2 |     let mut a: Option<u32> = None;
  |             ^
  |
  = help: maybe it is overwritten before being read?
  = note: `#[warn(unused_assignments)]` on by default

Rationale and extra context

No response

Other cases

If the initial value is used, then the warning goes away, suggesting that it should warn on that instead:

fn main() {
    let mut a: Option<u32> = None;
    let mut cl = move || {
        let _ = a;
        a = Some(42);
        a.take().unwrap()
    };
    println!("{}", cl())
}

Rust Version

rustc 1.89.0-nightly (d97326eab 2025-05-15)
binary: rustc
commit-hash: d97326eabfc3b2c33abcb08d6bc117aefa697cb7
commit-date: 2025-05-15
host: x86_64-unknown-linux-gnu
release: 1.89.0-nightly
LLVM version: 20.1.4

Anything else?

No response

@y86-dev y86-dev added A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels May 26, 2025
@fmease fmease added A-lints Area: Lints (warnings about flaws in source code) such as unused_mut. A-closures Area: Closures (`|…| { … }`) L-false-positive Lint: False positive (should not have fired). L-unused_assignments Lint: unused_assignments C-bug Category: This is a bug. and removed A-diagnostics Area: Messages for errors, warnings, and lints labels May 26, 2025
@hanna-kruppe
Copy link
Contributor

The diagnostic has a point, it just points at a misleading place in the code. The initial value of a, the one that’s assigned outside the closure and then moved into the closure, is never read. You could achieve the same effect with:

let cl = || {
    let mut a = Some(42);
    a.take().unwrap()
};

@fmease

This comment has been minimized.

@fmease

This comment has been minimized.

@fmease fmease added A-diagnostics Area: Messages for errors, warnings, and lints D-imprecise-spans Diagnostics: spans don't point to exactly the erroneous code and removed C-bug Category: This is a bug. L-false-positive Lint: False positive (should not have fired). labels May 26, 2025
@y86-dev
Copy link
Contributor Author

y86-dev commented May 26, 2025

The diagnostic has a point, it just points at a misleading place in the code. The initial value of a, the one that’s assigned outside the closure and then moved into the closure, is never read. You could achieve the same effect with:

let cl = || {
let mut a = Some(42);
a.take().unwrap()
};

Yeah that's correct, the example above was derive from a macro expansion, which is why it has to be created outside of the closure.

But this

fn main() {
    let mut a: Option<u32> = None;
    let mut cl = move || {
        let _ = a;
        a = Some(42);
        a.take().unwrap()
    };
    println!("{}", cl())
}

has no warning, suggesting that it should warn on the initial value None instead. Updated the issue with the information.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-closures Area: Closures (`|…| { … }`) A-diagnostics Area: Messages for errors, warnings, and lints A-lints Area: Lints (warnings about flaws in source code) such as unused_mut. D-imprecise-spans Diagnostics: spans don't point to exactly the erroneous code L-unused_assignments Lint: unused_assignments T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

3 participants