Description
There are several things we currently don't do that we could. It's not clear that these would have practical effects for any real program (or wouldn't negatively affect real programs by making llvm super confused), so all I can say is that these would be super cool.
Use Undefined Values in Other Primitives
- bool is a byte but can only contain 0 or 1
- char is 4 bytes but can only contain values in the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF]
Use Multiple Invalid-Value Fields
(&u8, &u8)
can be the same size as Option<Option<(&u8, &u8)>>
Support More than a Single Bit
- bool can support 254 enum variants
- char can support tons
Use all other fields as free bits when there exists another forbidden field
(&u8, u64)
supports 2^64 variants via the encoding (0, x)
Use the Fact that Void is Statically Unreachable
enum Void { }
cannot be instantiated, so any variant the contains Void
is statically unreachable, and therefore can be removed. So Option<Void>
can only be None
, and therefore can be zero-sized.
Support Enums that have More than One Non-C-Like Variant
enum Foo {
A(&u8, &u8),
B(&u8),
}
Can be represented without any tag as (&u8, *const u8)
via the following packing:
- self.1 is not null: A
- self.1 is null: B
Treat any True Discriminant Tags as a Type with Undefined Values
Option<Option<u32>>
can be "only" 8 bytes if the second Option stores its discriminant in the first Option's u32 tag.