Description
openedon Mar 6, 2020
I propose that we should have the following invariant: Whenever, anywhere in MIR, there is a field projection with some index i
, then i
is actually a valid field index in the (statically known) layout of the type being projected into.
Right now, this is not the case. This code:
pub enum Void {}
enum UninhabitedUnivariant { _Variant(Void), }
fn main() {
let _seed: UninhabitedUnivariant = None.unwrap();
match _seed {
UninhabitedUnivariant::_Variant(_x) => {}
}
}
generates the following MIR:
bb1: {
StorageDead(_2); // bb1[0]: scope 0 at src/main.rs:6:52: 6:53
StorageLive(_3); // bb1[1]: scope 1 at src/main.rs:8:41: 8:43
_3 = move ((_1 as _Variant).0: Void); // bb1[2]: scope 1 at src/main.rs:8:41: 8:43
StorageDead(_3); // bb1[3]: scope 1 at src/main.rs:9:5: 9:6
StorageDead(_1); // bb1[4]: scope 0 at src/main.rs:10:1: 10:2
return; // bb1[5]: scope 0 at src/main.rs:10:2: 10:2
}
but the layout of _Variant
is that of a union with 0 fields.
A consequence of this incoherence is that all codegen backends and Miri (and possibly more MIR consumers) all need to be on their guard when considering field projections, always protecting against the case where the projection is ill-formed (usually that happens by special-casing uninhabited types before considering the projection).
I think instead of putting that burden on every MIR consumer, we should fix either the layout or the MIR to not violate the invariant in the first place.
Cc @eddyb with whom I anyway recently talked about those odd Union
layouts. Is there some fundamental issue with the invariant I am proposing? Also Cc @oli-obk @wesleywiser
If we decide to go with this, we should
- Revert Do not ICE when matching an uninhabited enum's field #69753
- Check for other cases in Miri/const-prop that just work around such broken MIR/layout
- Check for the corresponding cases in codegen and other MIR consumers -- mostly, add assertion here.