[WIP]: Do not store tag in uninhabited enum variants, or in the single inhabited variant. by zachs18 · Pull Request #145337 · rust-lang/rust (original) (raw)
PR description is outdated. I'll update it if/when the MCP is accepted.
This PR contains 3 or 4 changes which could probably be split up:
First (first commit): split out into #145387
Second (second commit) (needed for the actual layout changes to be sound with offset_of! on uninhabited variants' fields): Keep track of uninhabited non-abset variants' layouts, even if we use an untagged (Variants::Single) or uninhabited (Variants::Empty) layout. This is necessary as otherwise offset_of! will "conjure" a layout for uninhabited variants where all fields are at offset 0, which conflicts with partial initialization1.
Third (sixth commit): Do not make space for the enum tag in uninhabited variants in the tagged enum layout calculation. This optimizes enums where the uninhabited variants are the largest, and reduces their size by up to the size of the tag. e.g. enum Foo { A, B(i32, !) } was 8 bytes A: (tag, uninit), B: (tag, i32, !) and is now 4 bytes A: (tag,), B: (i32, !). Additionally, enums with only zero-sized uninhabited variants are special-cased to return an uninhabited layout of the correct size and alignment without a tag at all, as otherwise we get weird edge cases2.
Fourth (seventh commit): Add an additional enum layout that does not encode a tag. This is similar to the existing "single-present-variant" optimization, but works even if some of the uninhabited variants are "present" (have non-1-ZST fields). This works by calculating the layout of the inhabited variant as a struct, and padding it to the maximum size and alignment necessary to fit each uninhabited variant.
The layout changes probably need an MCP and I haven't squashed fully, so draft for now.
r? ghost
Footnotes
- This isn't an issue before this PR because the layout algorithm only produces
Variants::EmptyorVariants::Singlewhen all uninhabited variants are "absent", i.e. have only 1-ZST fields ↩ - Specifically, without the special-case,
enum Foo { A(Aligned2Never), B(Aligned2Never) }got a size-0 layout with ani16tag field, which I assume would cause problems. ↩