In Rust, changes to a type’s alignment are not usually understood to be Breaking Changes™. Of course, that isn’t to say you can’t break safe, downstream code by changing the alignment of a type…
align_of
The mem::align_of
intrinsic is a safe function that provides the minimum alignment (in bytes) of any type. As with size_of
, downstream code should not rely on mem::align_of
producing a SemVer stable result, but that’s only a convention. Consider:
pub mod upstream {
#[repr(C)]
pub struct Foo {
bar: u8,
// uncommenting this field is a breaking change for `downstream`:
/* baz: u16 */
}
}
pub mod downstream {
use super::upstream::*;
const _: [(); 1] = [(); std::mem::align_of::<Foo>()];
}
error[E0308]: mismatched types
--> src/lib.rs:12:22
|
12 | const _: [(); 1] = [(); std::mem::align_of::<Foo>()];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an array with a fixed size of 1 element, found one with 2 elements
repr(transparent)
The repr(transparent)
attribute provides a mechanism for observing the alignment of a type. The repr(transparent)
attribute can be applied to types where:
- at most one field has size greater-than zero, and
- all other fields have minimum alignment equal to 1
…to specify that the annotated type’s layout is identical to that of the non-zero-sized field. Applying repr(transparent)
to a type with more than one field that has alignment >1 is a compile error:
#[repr(transparent)]
pub struct Foo {
bar: u8, // align = 1
baz: [u16; 0] // align = 2 (⚠)
}
error[E0691]: zero-sized field in transparent struct has alignment larger than 1
--> src/lib.rs:4:5
|
4 | baz: [u16; 0]
| ^^^^^^^^^^^^^ has alignment larger than 1
This requirement exists because even zero-sized fields affect the alignment (and thus padding) of the types they appear in.
Consequently, upstream changes that increase the alignment of ZST can break downstream code:
pub mod upstream {
#[repr(C)]
pub struct Foo {
bar: (),
// uncommenting this field is a breaking change for `downstream`:
/* baz: [u16; 0], */
}
}
pub mod downstream {
use super::upstream::*;
#[repr(transparent)]
struct Bar(u8, Foo);
}
error[E0691]: zero-sized field in transparent struct has alignment larger than 1
--> src/lib.rs:14:18
|
14 | struct Bar(u8, Foo);
| ^^^ has alignment larger than 1
You should therefore avoid #[repr(transparent)]
unless the ZST field types are documented to have a minimum alignment of 1.
Thanks to /u/CUViper for nudging me towards thinking about alignment-related snares!