Repository: rust
Issue: const destructor error when using `while let Some` with generic type
Labels: C-enhancement,T-compiler,A-MIR,A-const-eval

<!--
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
along with any information you feel relevant to replicating the bug.
-->

I tried this code: [play](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=ee1e8544eb63b71fa579fde05a00e925)

```rust
struct MyIterator<T>(std::marker::PhantomData<T>);

impl<T> MyIterator<T> {
    const fn next(&elf) -> Option<T> {
        None
    }
}

const fn consume<T>(x: MyIterator<T>) {
    while let Some(it) = x.next() {
        std::mem::forget(it);
    }
}
```

I expected to see this happen: compiles

Instead, this happened:

```
error[E0493]: destructor of `Option<T>` cannot be evaluated at compile-time
  --> src/lib.rs:12:26
   |
12 |     while let Some(it) = x.next() {
   |                          ^^^^^^^^ the destructor for this type cannot be evaluated in constant functions
13 |         std::mem::forget(it);
14 |     }
   |     - value is dropped here
```


This is a limitation in running checks on the MIR for dropping generic types. If we assert that `T: ~const Destruct`, we can get the MIR:

```rust
// MIR FOR CTFE
fn consume(_1: MyIterator<T>) -> () {
    debug x => _1;                       // in scope 0 at src/lib.rs:11:51: 11:56
    let mut _0: ();                      // return place in scope 0 at src/lib.rs:11:73: 11:73
    let mut _2: ();                      // in scope 0 at src/lib.rs:11:1: 15:2
    let mut _3: std::option::Option<T>;  // in scope 0 at src/lib.rs:12:26: 12:34
    let mut _4: &mut MyIterator<T>;      // in scope 0 at src/lib.rs:12:26: 12:34
    let mut _5: isize;                   // in scope 0 at src/lib.rs:12:15: 12:23
    let _7: ();                          // in scope 0 at src/lib.rs:13:9: 13:29
    let mut _8: T;                       // in scope 0 at src/lib.rs:13:26: 13:28
    let mut _9: !;                       // in scope 0 at src/lib.rs:12:5: 14:6
    let _10: ();                         // in scope 0 at src/lib.rs:12:5: 14:6
    let mut _11: !;                      // in scope 0 at src/lib.rs:12:5: 14:6
    let mut _12: isize;                  // in scope 0 at src/lib.rs:14:5: 14:6
    let mut _13: isize;                  // in scope 0 at src/lib.rs:14:5: 14:6
    let mut _14: isize;                  // in scope 0 at src/lib.rs:14:5: 14:6
    scope 1 {
        debug it => _6;                  // in scope 1 at src/lib.rs:12:20: 12:22
        let _6: T;                       // in scope 1 at src/lib.rs:12:20: 12:22
    }

    bb0: {
        goto -> bb1;                     // scope 0 at src/lib.rs:12:5: 14:6
    }

    bb1: {
        StorageLive(_3);                 // scope 1 at src/lib.rs:12:26: 12:34
        StorageLive(_4);                 // scope 1 at src/lib.rs:12:26: 12:34
        _4 = &mut _1;                    // scope 1 at src/lib.rs:12:26: 12:34
        ConstEvalCounter;                // scope 1 at src/lib.rs:12:26: 12:34
        _3 = MyIterator::<T>::next(move _4) -> bb2; // scope 1 at src/lib.rs:12:26: 12:34
                                         // mir::Constant
                                         // + span: src/lib.rs:12:28: 12:32
                                         // + literal: Const { ty: for<'a> fn(&'a mut MyIterator<T>) -> Option<T> {MyIterator::<T>::next}, val: Value(<ZST>) }
    }

    bb2: {
        StorageDead(_4);                 // scope 1 at src/lib.rs:12:33: 12:34
        _5 = discriminant(_3);           // scope 1 at src/lib.rs:12:15: 12:23
        switchInt(move _5) -> [1: bb3, otherwise: bb5]; // scope 1 at src/lib.rs:12:15: 12:23
    }

    bb3: {
        StorageLive(_6);                 // scope 1 at src/lib.rs:12:20: 12:22
        _6 = move ((_3 as Some).0: T);   // scope 1 at src/lib.rs:12:20: 12:22
        StorageLive(_7);                 // scope 1 at src/lib.rs:13:9: 13:29
        StorageLive(_8);                 // scope 1 at src/lib.rs:13:26: 13:28
        _8 = move _6;                    // scope 1 at src/lib.rs:13:26: 13:28
        ConstEvalCounter;                // scope 1 at src/lib.rs:13:9: 13:29
        _7 = std::mem::forget::<T>(move _8) -> [return: bb4, unwind: bb8]; // scope 1 at src/lib.rs:13:9: 13:29
                                         // mir::Constant
                                         // + span: src/lib.rs:13:9: 13:25
                                         // + literal: Const { ty: fn(T) {std::mem::forget::<T>}, val: Value(<ZST>) }
    }

    bb4: {
        StorageDead(_8);                 // scope 1 at src/lib.rs:13:28: 13:29
        StorageDead(_7);                 // scope 1 at src/lib.rs:13:29: 13:30
        _2 = const ();                   // scope 1 at src/lib.rs:12:35: 14:6
        StorageDead(_6);                 // scope 0 at src/lib.rs:14:5: 14:6
        _12 = discriminant(_3);          // scope 0 at src/lib.rs:14:5: 14:6
        StorageDead(_3);                 // scope 0 at src/lib.rs:14:5: 14:6
        ConstEvalCounter;                // scope 0 at src/lib.rs:12:5: 14:6
        goto -> bb1;                     // scope 0 at src/lib.rs:12:5: 14:6
    }

    bb5: {
        StorageLive(_10);                // scope 0 at src/lib.rs:12:5: 14:6
        _0 = const ();                   // scope 0 at src/lib.rs:12:5: 14:6
        StorageDead(_10);                // scope 0 at src/lib.rs:14:5: 14:6
        drop(_3) -> [return: bb6, unwind: bb7]; // scope 0 at src/lib.rs:14:5: 14:6
    }

    bb6: {
        StorageDead(_3);                 // scope 0 at src/lib.rs:14:5: 14:6
        return;                          // scope 0 at src/lib.rs:15:2: 15:2
    }

    bb7 (cleanup): {
        resume;                          // scope 0 at src/lib.rs:11:1: 15:2
    }

    bb8 (cleanup): {
        _14 = discriminant(_3);          // scope 0 at src/lib.rs:14:5: 14:6
        goto -> bb7;                     // scope 0 at src/lib.rs:14:5: 14:6
    }
}
```

Notice `drop(_3)` drops the `Option` even though we know it is `None` at that point.

Related: #92766