Code change:
<!-- Thank you for finding an Internal Compiler Error! If possible, try to provide a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for how to create smaller examples. --run this in miri to reproduce the ice: <!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongBacktrace</strong</summary<p</p</details
Looks like it tries to access the discriminant (field 0 of ), but then this case does not apply: The case does not apply because has size 8, but the field only has size 1. I didn't know types can have padding in them... in fact this is a type with layout where the size of the layout is bigger than the size of the scalar. This has me slightly worried about our code path which has less strict sanity checks. Is it possible to have a ScalarPair layout with one field where that one field covers both components of the pair and yes is smaller than the entire type? Miri (and CTFE) would go completely wrong on that.
Oh, turns out codegen uses the same logic: So I think a similar bug can somehow be triggered in codegen. I am just not sure how to make it call in the right way...
I am still missing something, the bug doesn't reproduce as often as it should... e.g., this one doesn't ICE but this one does Also I noticed that this type has ABI. do you know why lose their newtype layout optimizations with but do not? Should we really give enums a layout? Or is "Scalars do not have padding" part of the contract of layout computation?
FWIW, if I put this kind of sanity check also into Miri, things explode spectacularly. This type from memchr ends up with a immediate while having ABI. I suspect this is because even when the enum has layout, its variant (after a downcast) can have layout. That sounds like yet another bug in layout computation to me. EDIT: Also, just fixing the logic in will not be enough. We'd still be loading an 8-byte scalar which is partially uninit (yielding an entirely uninit scalar in Miri) and then try to get an integer out of that, which would raise UB. The assumption that scalars do not have padding is laced throughout Miri.
Not really a why in the sense you're asking for, but the layout computation makes the struct decision right here: For fieldless enums, is def missing an alignment check
So this is just a bug in layout computation then, and we are okay with enums losing their layout (and hence their niche)? That would be a big relief. ;)
I made that a separate issue: So this issue now is about some enums violating the invariant that layout types do not have padding.
here is already , so this is not the place where the alignment check is missing. I am not sure where is the right place though... However, I also cannot see any code in the enum path that would take into account , so I am probably missing something.
Actually the problem is the fix () for (the same code as this problem^^): that introduced the branch, which uses scalar layout even when it should not be used.
This is quite interesting, and I am not sure what to do. The problem is that on the one hand, must have layout since it has padding. on the other hand, since this enum has explicit discriminants, parts of the compiler expect that they can on it, which means it must have layout. It is impossible to satisfy both of these constraints together. any ideas for what to do here?
(Digging a bit deeper) it's not [just] about having explicit discriminants, but rather that enums can be the input to a cast and cast values are expected to be represented as immediates. Allowing on enums looks like a mistake... (we disallow , FWIW)
FWIW, here's basically the same bug during CTFE, though for some reason it doesn't cause an ICE: So we can have this as a testcase in rustc.

Related discussion:
text: fn main() { let aligned = Aligned::Zero; let fo = aligned as u8; <del> println!("foo {}",fo); </del> <ins> println!("foo {}", fo); assert_eq!(fo, 0); println!("{}", tou8(Aligned::Zero)); assert_eq!(tou8(Aligned::Zero), 0); } #[inline(never)] fn tou8(al: Aligned) -> u8 { // Cast behind a function call so ConstProp does not see it // (so that we can test codegen). al as u8 </ins> }