reference
reference copied to clipboard
Document field struct alignment guarantees?
This recently posted article makes that point that, because the default representation makes no guarantees of data layout, one must use write_unaligned to write to the fields of a struct when initializing it field by field.
This runs contrary to the the documentation of MaybeUninit about initializing a struct field by field, and also to what the nomicon has to say on the subject:
By default, composite structures have an alignment equal to the maximum of their fields' alignments. Rust will consequently insert padding where necessary to ensure that all fields are properly aligned and that the overall type's size is a multiple of its alignment.
Should we amend the reference to either link to the nomicon for more details, or to specify that fields that can be accessed in a struct are properly aligned (no write_unaligned necessary)?
I'd propose a formulation, but I'm unsure about e.g. stuff like ZST...
I'd add:
Nominal types without a repr attribute have the default representation. Informally, this representation is also called the rust representation.
Accessible fields of a struct or enum in the default representation are guaranteed to be properly aligned.
There are no other guarantees of data layout made by this representation.
What do you think?
I don't know the precise wording the reference likes, but yes repr(rust) must align all of its fields.
Zero-sized-types must also be completely aligned. Most have align 1 so they are trivially always aligned. The major exception is [T; 0] which is size 0 but aligned to T. In the times before Rust had proper alignment attributes, this was relied upon to specify a struct needed more alignment than the other fields suggested.
There is otherwise no burden for keeping ZSTs aligned in repr(rust) because the compiler is always free to logically reorder them to the start of the struct which has maximum alignment. Because they have no size, they do not "waste" that alignment and the non-ZST fields can still start at offset 0.
because the default representation makes no guarantees of data layout, one must use write_unaligned to write to the fields of a struct when initializing it field by field.
Ah, that is interpreting "no guarantees" way too far. But I agree it is probably worth being more explicit here.
Some things are definitely guaranteed:
- The fields do not overlap.
- Each field has the alignment that is required by its type.
These guarantees are required for basic soundness, they are so fundamental that presumably the author of the "no guarantee" line could not imagine a violation even being considered. ;)
As the author of that line, it's as @RalfJung says, except that I did know those two requirements at the time; I just failed to convey them anywhere at all. Tuple representation has the same problems.