Skip to content

Commit

Permalink
doc: fix deprecated doc of attribute packed
Browse files Browse the repository at this point in the history
The Rust language reference (and my experience, proofed by tests) says, that `packed(n)` gives you the ability to align the struct too.

https://doc.rust-lang.org/reference/type-layout.html
  • Loading branch information
phip1611 committed Nov 9, 2021
1 parent 2d66852 commit ebdd236
Showing 1 changed file with 31 additions and 13 deletions.
44 changes: 31 additions & 13 deletions src/other-reprs.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,26 +112,43 @@ assert_eq!(16, size_of::<MyReprOption<&u16>>());

This optimization still applies to fieldless enums with an explicit `repr(u*)`, `repr(i*)`, or `repr(C)`.

## repr(packed)
## repr(packed(n))

`repr(packed)` forces Rust to strip any padding, and only align the type to a
byte. This may improve the memory footprint, but will likely have other negative
side-effects.
`repr(packed(n))` forces the Rust compiler to strip any padding between fields, and align the type, hence, the first field, at least to a
[`n`-byte boundary][rust-reference-type-layout] (where `n` is a power of two). `repr(packed)` is equivalent
to `repr(packed(1))`.

This `repr`-attribute is a modifier on `repr(C)` and `repr(Rust)`, but is incompatible with `align(n)`. It may improve
the memory footprint and is useful in scenarios, where you need exact control over the memory layout
(such as constructing network packets).

In particular, most architectures *strongly* prefer values to be aligned. This
may mean the unaligned loads are penalized (x86), or even fault (some ARM
chips). For simple cases like directly loading or storing a packed field, the
compiler might be able to paper over alignment issues with shifts and masks.
However if you take a reference to a packed field, it's unlikely that the
compiler will be able to emit code to avoid an unaligned load.
chips). Fields of packed structs are not guaranteed to be properly aligned, and creating a reference to them is
undefined behavior (even if that reference is never dereferenced). [As this can cause undefined behavior][ub loads],
the lint has been implemented and it will become a hard error in the future (not yet in Rust nightly 1.58).

The workaround is either to implement unsafe functionality on top of pointers or to copy the value. See the example
below:

[As this can cause undefined behavior][ub loads], the lint has been implemented
and it will become a hard error.
```rust
#[repr(C, packed(2))]
struct Foo {
a: u32,
}

`repr(packed)` is not to be used lightly. Unless you have extreme requirements,
this should not be used.
impl Foo {
/// Okay because it's a safe copy
fn a(&self) -> u32 {
self.a
}
/// Warning and future hard error
fn a_ref(&self) -> &u32 {
&self.a
}
}
```

This repr is a modifier on `repr(C)` and `repr(Rust)`.

## repr(align(n))

Expand All @@ -153,3 +170,4 @@ This is a modifier on `repr(C)` and `repr(Rust)`. It is incompatible with
[really-tagged]: https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md
[rust-bindgen]: https://rust-lang.github.io/rust-bindgen/
[cbindgen]: https://github.com/eqrion/cbindgen
[rust-reference-type-layout]: https://doc.rust-lang.org/reference/type-layout.html

0 comments on commit ebdd236

Please # to comment.