Repository: rust
Issue: Unexpectedly long lifetime of values created in let bindings
Labels: C-enhancement,T-compiler,A-control-flow

Today I stumbled over an unexpected deadlock related to lifetime scoping of values inside a let binding.

It seems like values created in a let binding are kept alive until the end of the inner block, even if the value is surrounded by a block.

I'm not sure if this is the expected behaviour, but it is counter to my expectation of "values live until the end of the surrounding block".

To illustrate:

```rust
use std::sync::Mutex;

fn main() {
    let m = Mutex::new(Some(true));
    test_mutex(&m)
}

fn test_mutex(m: &Mutex<Option<bool>>) {
    if let Some(x) = { (*m.lock().unwrap()).clone() } {
        //             ^^^^^^^^^^^^^^^^^^^^^^^^^
        //             Mutex is locked, inner value is cloned.

        // Ensure x is actually bool, not a reference.
        let x: bool = x;
        // do expensive work...
        *m.lock().unwrap() = Some(!x);
        // ^^^^^^
        // DEADLOCK!
    }
}
```

My expectation was that that the lock would go out of scope at the beginning of the inner block, but it does not and is kept alive until the inner block ends, leading to the deadlock - as can be verified by looking at the MIR: 

<details>
   <summary> MIR Output</summary>
<pre>
// WARNING: This output format is intended for human consumers only
// and is subject to change without notice. Knock yourself out.
fn main() -> () {
    let mut _0: ();                      // return place in scope 0 at [src/main.rs:3:11: 3:11](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let _1: std::sync::Mutex<std::option::Option<bool>>; // in scope 0 at [src/main.rs:4:9: 4:10](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _2: std::option::Option<bool>; // in scope 0 at [src/main.rs:4:24: 4:34](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _3: &std::sync::Mutex<std::option::Option<bool>>; // in scope 0 at [src/main.rs:5:16: 5:18](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let _4: &std::sync::Mutex<std::option::Option<bool>>; // in scope 0 at [src/main.rs:5:16: 5:18](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    scope 1 {
        debug m => _1;                   // in scope 1 at [src/main.rs:4:9: 4:10](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    }

    bb0: {
        Deinit(_2);                      // scope 0 at [src/main.rs:4:24: 4:34](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        ((_2 as Some).0: bool) = const true; // scope 0 at [src/main.rs:4:24: 4:34](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        discriminant(_2) = 1;            // scope 0 at [src/main.rs:4:24: 4:34](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        _1 = Mutex::<Option<bool>>::new(move _2) -> bb1; // scope 0 at [src/main.rs:4:13: 4:35](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // mir::Constant
                                         // + span: [src/main.rs:4:13: 4:23](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // + user_ty: UserType(0)
                                         // + literal: Const { ty: fn(Option<bool>) -> Mutex<Option<bool>> {Mutex::<Option<bool>>::new}, val: Value(Scalar(<ZST>)) }
    }

    bb1: {
        _4 = &_1;                        // scope 1 at [src/main.rs:5:16: 5:18](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        _3 = _4;                         // scope 1 at [src/main.rs:5:16: 5:18](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        _0 = test_mutex(move _3) -> bb2; // scope 1 at [src/main.rs:5:5: 5:19](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // mir::Constant
                                         // + span: [src/main.rs:5:5: 5:15](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // + literal: Const { ty: for<'r> fn(&'r Mutex<Option<bool>>) {test_mutex}, val: Value(Scalar(<ZST>)) }
    }

    bb2: {
        return;                          // scope 0 at [src/main.rs:6:2: 6:2](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    }
}

fn test_mutex(_1: &Mutex<Option<bool>>) -> () {
    debug m => _1;                       // in scope 0 at [src/main.rs:8:15: 8:16](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _0: ();                      // return place in scope 0 at [src/main.rs:8:40: 8:40](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _2: std::option::Option<bool>; // in scope 0 at [src/main.rs:9:22: 9:70](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let _3: std::option::Option<bool>;   // in scope 0 at [src/main.rs:9:28: 9:33](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _4: &std::option::Option<bool>; // in scope 0 at [src/main.rs:9:36: 9:61](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let _5: &std::option::Option<bool>;  // in scope 0 at [src/main.rs:9:36: 9:61](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _6: &std::sync::MutexGuard<std::option::Option<bool>>; // in scope 0 at [src/main.rs:9:36: 9:61](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let _7: std::sync::MutexGuard<std::option::Option<bool>>; // in scope 0 at [src/main.rs:9:36: 9:53](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _8: std::result::Result<std::sync::MutexGuard<std::option::Option<bool>>, std::sync::PoisonError<std::sync::MutexGuard<std::option::Option<bool>>>>; // in scope 0 at [src/main.rs:9:36: 9:44](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _9: &std::sync::Mutex<std::option::Option<bool>>; // in scope 0 at [src/main.rs:9:36: 9:44](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _10: isize;                  // in scope 0 at [src/main.rs:9:12: 9:19](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let _11: bool;                       // in scope 0 at [src/main.rs:9:17: 9:18](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let _12: bool;                       // in scope 0 at [src/main.rs:14:13: 14:14](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _13: std::option::Option<bool>; // in scope 0 at [src/main.rs:16:30: 16:38](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _14: bool;                   // in scope 0 at [src/main.rs:16:35: 16:37](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _15: bool;                   // in scope 0 at [src/main.rs:16:36: 16:37](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _16: &mut std::option::Option<bool>; // in scope 0 at [src/main.rs:16:9: 16:27](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _17: &mut std::sync::MutexGuard<std::option::Option<bool>>; // in scope 0 at [src/main.rs:16:10: 16:27](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _18: std::sync::MutexGuard<std::option::Option<bool>>; // in scope 0 at [src/main.rs:16:10: 16:27](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _19: std::result::Result<std::sync::MutexGuard<std::option::Option<bool>>, std::sync::PoisonError<std::sync::MutexGuard<std::option::Option<bool>>>>; // in scope 0 at [src/main.rs:16:10: 16:18](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _20: &std::sync::Mutex<std::option::Option<bool>>; // in scope 0 at [src/main.rs:16:10: 16:18](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    scope 1 {
        debug value => _3;               // in scope 1 at [src/main.rs:9:28: 9:33](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    }
    scope 2 {
        debug x => _11;                  // in scope 2 at [src/main.rs:9:17: 9:18](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    }
    scope 3 {
        debug x => _12;                  // in scope 3 at [src/main.rs:14:13: 14:14](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    }

    bb0: {
        _9 = _1;                         // scope 0 at [src/main.rs:9:36: 9:44](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        _8 = Mutex::<Option<bool>>::lock(move _9) -> bb1; // scope 0 at [src/main.rs:9:36: 9:44](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // mir::Constant
                                         // + span: [src/main.rs:9:38: 9:42](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // + literal: Const { ty: for<'r> fn(&'r Mutex<Option<bool>>) -> Result<MutexGuard<'r, Option<bool>>, PoisonError<MutexGuard<'r, Option<bool>>>> {Mutex::<Option<bool>>::lock}, val: Value(Scalar(<ZST>)) }
    }

    bb1: {
        _7 = Result::<MutexGuard<Option<bool>>, PoisonError<MutexGuard<Option<bool>>>>::unwrap(move _8) -> bb2; // scope 0 at [src/main.rs:9:36: 9:53](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // mir::Constant
                                         // + span: [src/main.rs:9:45: 9:51](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // + literal: Const { ty: fn(Result<MutexGuard<Option<bool>>, PoisonError<MutexGuard<Option<bool>>>>) -> MutexGuard<Option<bool>> {Result::<MutexGuard<Option<bool>>, PoisonError<MutexGuard<Option<bool>>>>::unwrap}, val: Value(Scalar(<ZST>)) }
    }

    bb2: {
        _6 = &_7;                        // scope 0 at [src/main.rs:9:36: 9:61](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        _5 = <MutexGuard<Option<bool>> as Deref>::deref(move _6) -> [return: bb3, unwind: bb12]; // scope 0 at [src/main.rs:9:36: 9:61](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // mir::Constant
                                         // + span: [src/main.rs:9:36: 9:61](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // + literal: Const { ty: for<'r> fn(&'r MutexGuard<Option<bool>>) -> &'r <MutexGuard<Option<bool>> as Deref>::Target {<MutexGuard<Option<bool>> as Deref>::deref}, val: Value(Scalar(<ZST>)) }
    }

    bb3: {
        _4 = _5;                         // scope 0 at [src/main.rs:9:36: 9:61](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        _3 = <Option<bool> as Clone>::clone(move _4) -> [return: bb4, unwind: bb12]; // scope 0 at [src/main.rs:9:36: 9:61](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // mir::Constant
                                         // + span: [src/main.rs:9:54: 9:59](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // + literal: Const { ty: for<'r> fn(&'r Option<bool>) -> Option<bool> {<Option<bool> as Clone>::clone}, val: Value(Scalar(<ZST>)) }
    }

    bb4: {
        drop(_7) -> bb5;                 // scope 0 at [src/main.rs:9:61: 9:62](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    }

    bb5: {
        _2 = _3;                         // scope 1 at [src/main.rs:9:63: 9:68](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        _10 = discriminant(_2);          // scope 0 at [src/main.rs:9:12: 9:19](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        switchInt(move _10) -> [1_isize: bb6, otherwise: bb10]; // scope 0 at [src/main.rs:9:12: 9:19](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    }

    bb6: {
        _11 = ((_2 as Some).0: bool);    // scope 0 at [src/main.rs:9:17: 9:18](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        _12 = _11;                       // scope 0 at [src/main.rs:14:23: 14:24](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        _15 = _12;                       // scope 3 at [src/main.rs:16:36: 16:37](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        _14 = Not(move _15);             // scope 3 at [src/main.rs:16:35: 16:37](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        Deinit(_13);                     // scope 3 at [src/main.rs:16:30: 16:38](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        ((_13 as Some).0: bool) = move _14; // scope 3 at [src/main.rs:16:30: 16:38](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        discriminant(_13) = 1;           // scope 3 at [src/main.rs:16:30: 16:38](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        _20 = _1;                        // scope 3 at [src/main.rs:16:10: 16:18](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        _19 = Mutex::<Option<bool>>::lock(move _20) -> bb7; // scope 3 at [src/main.rs:16:10: 16:18](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // mir::Constant
                                         // + span: [src/main.rs:16:12: 16:16](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // + literal: Const { ty: for<'r> fn(&'r Mutex<Option<bool>>) -> Result<MutexGuard<'r, Option<bool>>, PoisonError<MutexGuard<'r, Option<bool>>>> {Mutex::<Option<bool>>::lock}, val: Value(Scalar(<ZST>)) }
    }

    bb7: {
        _18 = Result::<MutexGuard<Option<bool>>, PoisonError<MutexGuard<Option<bool>>>>::unwrap(move _19) -> bb8; // scope 3 at [src/main.rs:16:10: 16:27](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // mir::Constant
                                         // + span: [src/main.rs:16:19: 16:25](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // + literal: Const { ty: fn(Result<MutexGuard<Option<bool>>, PoisonError<MutexGuard<Option<bool>>>>) -> MutexGuard<Option<bool>> {Result::<MutexGuard<Option<bool>>, PoisonError<MutexGuard<Option<bool>>>>::unwrap}, val: Value(Scalar(<ZST>)) }
    }

    bb8: {
        _17 = &mut _18;                  // scope 3 at [src/main.rs:16:10: 16:27](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        _16 = <MutexGuard<Option<bool>> as DerefMut>::deref_mut(move _17) -> [return: bb9, unwind: bb11]; // scope 3 at [src/main.rs:16:9: 16:27](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // mir::Constant
                                         // + span: [src/main.rs:16:9: 16:27](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // + literal: Const { ty: for<'r> fn(&'r mut MutexGuard<Option<bool>>) -> &'r mut <MutexGuard<Option<bool>> as Deref>::Target {<MutexGuard<Option<bool>> as DerefMut>::deref_mut}, val: Value(Scalar(<ZST>)) }
    }

    bb9: {
        (*_16) = move _13;               // scope 3 at [src/main.rs:16:9: 16:38](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        drop(_18) -> bb10;               // scope 3 at [src/main.rs:16:38: 16:39](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    }

    bb10: {
        return;                          // scope 0 at [src/main.rs:20:2: 20:2](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    }

    bb11 (cleanup): {
        drop(_18) -> bb13;               // scope 3 at [src/main.rs:16:38: 16:39](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    }

    bb12 (cleanup): {
        drop(_7) -> bb13;                // scope 0 at [src/main.rs:9:61: 9:62](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    }

    bb13 (cleanup): {
        resume;                          // scope 0 at [src/main.rs:8:1: 20:2](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    }
}
</pre>
   </details>


In contrast, this code works as expected: `if let Some(x) = { let value = m.lock().unwrap().clone(); value } {`

This seems very counter-intuitive if your assumption is that block = lifetime scope.

Maybe it's not treated as a block because it's a single expression?

`rustc 1.63.0-nightly (e09449220 2022-05-31)`