Open
Description
I tried this code: play
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:
// 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