rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
96.96k stars 12.53k forks source link

Incorrect let_underscore_drop warning on type without Drop implementation #130430

Open Elrendio opened 4 days ago

Elrendio commented 4 days ago

I tried this code:

#![deny(let_underscore_drop)]

fn main() {
    let _ = MyStruct {
        field: vec![1, 2, 3],
    };
}

struct MyStruct {
    field: Vec<usize>,
}

I got this warning:

error: non-binding let on a type that implements `Drop`
 --> src/main.rs:4:5
  |
4 | /     let _ = MyStruct {
5 | |         field: vec![1, 2, 3],
6 | |     };
  | |______^
  |
note: the lint level is defined here
 --> src/main.rs:1:9
  |
1 | #![deny(let_underscore_drop)]
  |         ^^^^^^^^^^^^^^^^^^^
help: consider binding to an unused variable to avoid immediately dropping the value
  |
4 |     let _unused = MyStruct {
  |         ~~~~~~~
help: consider immediately dropping the value
  |
4 ~     drop(MyStruct {
5 |         field: vec![1, 2, 3],
6 ~     });
  |

However, there is no Drop impl on the type, so the error message is misleading. It is true however that there is a destructor, as defined here: https://doc.rust-lang.org/stable/std/ops/trait.Drop.html

That being said, it's insiginificant for all underlying types (only #[may_dangle] destructor of Vec and Copy type in the Vec), so ideally the warning still wouldn't even show.

Meta

rustc --version --verbose:

rustc 1.80.1 (3f5fd8dd4 2024-08-06)
binary: rustc
commit-hash: 3f5fd8dd41153bc5fdca9427e9e05be2c767ba23
commit-date: 2024-08-06
host: x86_64-unknown-linux-gnu
release: 1.80.1
LLVM version: 18.1.7
Backtrace

``` Compiling MinimalReproNonBindingLetDrop v0.1.0 (/home/elrendio/Stockly/MinimalReproNonBindingLetDrop) warning: field `field` is never read --> src/main.rs:10:5 | 9 | struct MyStruct { | -------- field in this struct 10 | field: Vec, | ^^^^^ | = note: `#[warn(dead_code)]` on by default error: non-binding let on a type that implements `Drop` --> src/main.rs:4:5 | 4 | / let _ = MyStruct { 5 | | field: vec![1, 2, 3], 6 | | }; | |______^ | note: the lint level is defined here --> src/main.rs:1:9 | 1 | #![deny(let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^ help: consider binding to an unused variable to avoid immediately dropping the value | 4 | let _unused = MyStruct { | ~~~~~~~ help: consider immediately dropping the value | 4 ~ drop(MyStruct { 5 | field: vec![1, 2, 3], 6 ~ }); | warning: `MinimalReproNonBindingLetDrop` (bin "MinimalReproNonBindingLetDrop") generated 1 warning error: could not compile `MinimalReproNonBindingLetDrop` (bin "MinimalReproNonBindingLetDrop") due to 1 previous error; 1 warning emitted ```

compiler-errors commented 4 days ago

Well, even if the T parameter of Vec<T> is #[may_dangle], it still has a side-effect (deallocates memory). I don't think we need this special-casing. I do think the diagnostic is a bit misleading and should just say "has a destructor" or "has side-effects when dropped".

Is there a more practical code example for why you'd want to suppress this error? The example you gave is a bit artificial, so it's a hard to motivate why we'd want to suppress this code since it really could be rewritten to be clearer.