Suggest _ instead of let _ when unused_must_use is triggered

This is purely a style recommendation, but it would be nice if the compiler suggested to assign a #[must_use] value to _ instead of let _. Are there any drawbacks? I don't know the policy of compiler suggestions as it pertains to MSRV, but the only reason I can think this shouldn't happen is that the suggestion won't work for rustc before 1.59.

Specifically I'm suggesting that the below code:

#![expect(dead_code, reason = "illustrative example")]
fn foo() -> Result<(), u32> {
    Ok(())
}
fn bar() {
    foo();
}

cause the compiler to emit the suggestion

help: use `_ = ...` to ignore the resulting value
  |
6 |     _ = foo();
  |     +++++++

instead of

help: use `let _ = ...` to ignore the resulting value
  |
6 |     let _ = foo();
  |     +++++++
4 Likes

While there shouldn't be a semantic difference, I don't think there's sufficient agreement that this is the preferred style at this point in time.

I expect we've recommended let _ = expr because of inertia from versions that don't support _ = expr, and haven't done any evaluation of preferred style.

10 Likes

It's still very unknown and I've certainly had reviewers who preferred me using let _ = (and I don't care too much either way). If a bare _ = becomes the preferred style it should definitely have a lint nudging people to use it.

fwiw if you need to deal with a lot of these like me, I decided to use some_result().log()? to actually consume the error and make it a noop on release, of course the name of the method depends on the type you are discarding.

In the end the preferred style is up to the maintainer no matter what rustc suggests. You can request a new lint in Clippy, likely in the restriction group, that recommends changing let _ to _. I was also informed that they're technically not semantically equivalent in particular let _ is subject to temporary lifetime extension while _ is not:

struct Foo;
impl Drop for Foo {
    fn drop(&mut self) {
        println!("dropped Foo");
    }
}
struct Bar;
impl Drop for Bar {
    fn drop(&mut self) {
        println!("dropped Bar");
    }
}
struct Fizz;
impl Drop for Fizz {
    fn drop(&mut self) {
        println!("dropped Fizz");
    }
}
fn main() {
    // `Foo` gets dropped immediately.
    let _ = Foo;
    // `Bar` gets dropped last.
    let _ = &Bar;
    // `Fizz` gets dropped immediately.
    _ = &Fizz;
}

This means even if such a lint were added, the suggestion shouldn't be blindly applied due to possible semantic differences.

1 Like

If the goal is to raise awareness then adding it to the restriction group in clippy is tantamount to not adding it at all. Relatively few people dig into those. Which is absolutely fine if rust's style team has no particular preference here. In which case either option is ok.

In any case. if a lint is added then it should take to avoid making suggestion that change program behaviour. But that's always true for lints.