Motivation
Currently, all ADTs in Rust have undef
padding. This means that each particular value of an ADT may be represented in many ways as a bit-pattern.
This forms a problem for 2 reasons
- The bit-pattern of an ADT can’t be used as a key in maps, because multiple such values might exist.
- The ADT can’t be used for “memcpy serialization”, because that would leak potentially-sensitive stack data.
These problems can’t easily be bypassed - because padding is always treated as undef
, merely moving an ADT rerandomizes the padding. You have to write a potentially-expensive translation function, which has to branch on the variant in the case of an enum.
Design
Add a #[single_repr]
attribute to ADTs.
#[single_repr]
struct Foo { .. }
#[single_repr]
enum Foo { .. }
#[single_repr]
union Foo { .. }
An ADT with a #[single_repr]
has a single bit-pattern for each series of bit-patterns for fields. For #[repr(C)]
, this is defined to be the bit-pattern with all padding 0.
Loading (that looks like a better name for my VExpr::Use
, bikeshed) a value of that ADT with a non-canonical bitpattern is UB.
Of course, if one of the fields has multiple bit-patterns, that would be preserved. We should have a lint against that.