Repository: rust
Issue: Behavior of `let _ =` for captured variables in closure can be *very* strange
Labels: A-closures,T-compiler,C-bug

In a project I'm working on, there was code like the following:

```rust
let closure: Box<dyn Fn()> = {
    // First we set up some kind of handle to a running task... this could be any RAII value or any
    // handle, just something we need to keep alive.  The type does not implement Copy.
    let handle = ...;

    // We need to create a closure and keep the handle alive for as long as the closure, so we move
    // it into the closure.
    Box::new(move || {
        // We need to tell rust that the handle should be moved into the closure, so just use it
        // somehow.
        let _ = handle;
    })
};
```

I can't bisect this right now across rust versions, but I could *swear* that at some point the behavior of this was to move `handle` into the closure and keep it alive until the closure was dropped.  That is not the case at least as of rust 1.60, as of the current rust, the `handle` value is dropped immediately when the enclosing block ends, so to fix this bug, the code was changed like this:

```rust
let closure: Box<dyn Fn()> = {
    let handle = ...;
    Box::new(move || {
        // Change `let _ = handle;` into `let _ = &handle;`
        let _ = &handle;
    })
};
```

This behaves as expected and keeps the `handle` value alive as long as the closure is alive.

But, the original situation is still strange to me.  Previously to this, I would have expected `let _ = x;` to be equivalent to `mem::drop(x);`, but that is not the case!  Replacing `let _ = handle;` with `mem::drop(handle);` actually makes the original code not compile at all, and this makes complete sense!  The handle value does not implement Copy, so by calling drop on it, you've moved the non-Copy value into a closure that is expected to implement `Fn()`, so you can't drop the one value once per closure call.  If using `let _ = x;` here was a compiler error, everything would make sense to me.

The behavior can be summarized like this:

```rust
fn main() {
    struct Droppy;
    impl Drop for Droppy {
        fn drop(&mut self) {
            println!("drop")
        }
    }

    let f: Box<dyn Fn()> = {
        let d = Droppy;
        Box::new(move || {
            // Case 1: This makes sense that this causes `d` to be moved into the closure and not
            // dropped until the closure is dropped.
            // let _ = &d;
            
            // Case 2: This is a compiler error because `Droppy` is not Copy, makes sense.
            // std::mem::drop(d);
            
            // Case 3: This compiles and drops `d` at the end of the enclosing block, *before* the
            // closure is even called.  This is very strange.
            let _ = d;
        })
    };

    println!("start");
    f();
    println!("end");
}
```

case 1 prints
```
start
end
drop
```
 
case 2 does not compile, with
```cannot move out of `d`, a captured variable in an `Fn` closure```

case 3 prints
```
drop
start
end
```

I'm not sure if this is a bug or whether this behavior *truly* changed at some previous rust version or whether case 3 above should also be a compiler error, but this behavior is very surprising.

It also wouldn't surprise me if this was already a known bug and I have just completely failed to search for it properly, if this is a duplicate or already known then I apologize for the noise, but it's pretty hard to search for.  Sorry if that's the case!