diff --git a/src/type-layout.md b/src/type-layout.md
index cefa1dc11..c33f0e442 100644
--- a/src/type-layout.md
+++ b/src/type-layout.md
@@ -2,17 +2,12 @@ r[layout]
# Type Layout
r[layout.intro]
-The layout of a type is its size, alignment, and the relative offsets of its
-fields. For enums, how the discriminant is laid out and interpreted is also part
-of type layout.
+The layout of a type is its size, alignment, and the relative offsets of its fields. For enums, how the discriminant is laid out and interpreted is also part of type layout.
r[layout.guarantees]
-Type layout can be changed with each compilation. Instead of trying to document
-exactly what is done, we only document what is guaranteed today.
+Type layout can be changed with each compilation. Instead of trying to document exactly what is done, we only document what is guaranteed today.
-Note that even types with the same layout can still differ in how they are passed
-across function boundaries. For function call ABI compatibility of types,
-see [here][fn-abi-compatibility].
+Note that even types with the same layout can still differ in how they are passed across function boundaries. For function call ABI compatibility of types, see [here][fn-abi-compatibility].
r[layout.properties]
## Size and Alignment
@@ -20,28 +15,13 @@ r[layout.properties]
All values have an alignment and size.
r[layout.properties.align]
-The *alignment* of a value specifies what addresses are valid to store the value
-at. A value of alignment `n` must only be stored at an address that is a
-multiple of n. For example, a value with an alignment of 2 must be stored at an
-even address, while a value with an alignment of 1 can be stored at any address.
-Alignment is measured in bytes, and must be at least 1, and always a power of 2.
-The alignment of a value can be checked with the [`align_of_val`] function.
+The *alignment* of a value specifies what addresses are valid to store the value at. A value of alignment `n` must only be stored at an address that is a multiple of n. For example, a value with an alignment of 2 must be stored at an even address, while a value with an alignment of 1 can be stored at any address. Alignment is measured in bytes, and must be at least 1, and always a power of 2. The alignment of a value can be checked with the [`align_of_val`] function.
r[layout.properties.size]
-The *size* of a value is the offset in bytes between successive elements in an
-array with that item type including alignment padding. The size of a value is
-always a multiple of its alignment. Note that some types are zero-sized; 0 is
-considered a multiple of any alignment (for example, on some platforms, the type
-`[u16; 0]` has size 0 and alignment 2). The size of a value can be checked with
-the [`size_of_val`] function.
+The *size* of a value is the offset in bytes between successive elements in an array with that item type including alignment padding. The size of a value is always a multiple of its alignment. Note that some types are zero-sized; 0 is considered a multiple of any alignment (for example, on some platforms, the type `[u16; 0]` has size 0 and alignment 2). The size of a value can be checked with the [`size_of_val`] function.
r[layout.properties.sized]
-Types where all values have the same size and alignment, and both are known at
-compile time, implement the [`Sized`] trait and can be checked with the
-[`size_of`] and [`align_of`] functions. Types that are not [`Sized`] are known
-as [dynamically sized types]. Since all values of a `Sized` type share the same
-size and alignment, we refer to those shared values as the size of the type and
-the alignment of the type respectively.
+Types where all values have the same size and alignment, and both are known at compile time, implement the [`Sized`] trait and can be checked with the [`size_of`] and [`align_of`] functions. Types that are not [`Sized`] are known as [dynamically sized types]. Since all values of a `Sized` type share the same size and alignment, we refer to those shared values as the size of the type and the alignment of the type respectively.
r[layout.primitive]
## Primitive Data Layout
@@ -63,30 +43,22 @@ The size of most primitives is given in this table.
| `char` | 4 |
r[layout.primitive.size-int]
-`usize` and `isize` have a size big enough to contain every address on the
-target platform. For example, on a 32 bit target, this is 4 bytes, and on a 64
-bit target, this is 8 bytes.
+`usize` and `isize` have a size big enough to contain every address on the target platform. For example, on a 32 bit target, this is 4 bytes, and on a 64 bit target, this is 8 bytes.
r[layout.primitive.align]
-The alignment of primitives is platform-specific.
-In most cases, their alignment is equal to their size, but it may be less.
-In particular, `i128` and `u128` are often aligned to 4 or 8 bytes even though
-their size is 16, and on many 32-bit platforms, `i64`, `u64`, and `f64` are only
-aligned to 4 bytes, not 8.
+The alignment of primitives is platform-specific. In most cases, their alignment is equal to their size, but it may be less. In particular, `i128` and `u128` are often aligned to 4 or 8 bytes even though their size is 16, and on many 32-bit platforms, `i64`, `u64`, and `f64` are only aligned to 4 bytes, not 8.
r[layout.pointer]
## Pointers and References Layout
r[layout.pointer.intro]
-Pointers and references have the same layout. Mutability of the pointer or
-reference does not change the layout.
+Pointers and references have the same layout. Mutability of the pointer or reference does not change the layout.
r[layout.pointer.thin]
Pointers to sized types have the same size and alignment as `usize`.
r[layout.pointer.unsized]
-Pointers to unsized types are sized. The size and alignment is guaranteed to be
-at least equal to the size and alignment of a pointer.
+Pointers to unsized types are sized. The size and alignment is guaranteed to be at least equal to the size and alignment of a pointer.
> [!NOTE]
> Though you should not rely on this, all pointers to DSTs are currently twice the size of the size of `usize` and have the same alignment.
@@ -94,9 +66,7 @@ at least equal to the size and alignment of a pointer.
r[layout.array]
## Array Layout
-An array of `[T; N]` has a size of `size_of::() * N` and the same alignment
-of `T`. Arrays are laid out so that the zero-based `nth` element of the array
-is offset from the start of the array by `n * size_of::()` bytes.
+An array of `[T; N]` has a size of `size_of::() * N` and the same alignment of `T`. Arrays are laid out so that the zero-based `nth` element of the array is offset from the start of the array by `n * size_of::()` bytes.
r[layout.slice]
## Slice Layout
@@ -118,8 +88,7 @@ r[layout.tuple.general]
Tuples are laid out according to the [`Rust` representation][`Rust`].
r[layout.tuple.unit]
-The exception to this is the unit tuple (`()`), which is guaranteed as a
-zero-sized type to have a size of 0 and an alignment of 1.
+The exception to this is the unit tuple (`()`), which is guaranteed as a zero-sized type to have a size of 0 and an alignment of 1.
r[layout.trait-object]
## Trait Object Layout
@@ -138,8 +107,7 @@ r[layout.repr]
## Representations
r[layout.repr.intro]
-All user-defined composite types (`struct`s, `enum`s, and `union`s) have a
-*representation* that specifies what the layout is for the type.
+All user-defined composite types (`struct`s, `enum`s, and `union`s) have a *representation* that specifies what the layout is for the type.
r[layout.repr.kinds]
The possible representations for a type are:
@@ -150,82 +118,123 @@ The possible representations for a type are:
- [`transparent`]
r[layout.repr.attribute]
-The representation of a type can be changed by applying the `repr` attribute
-to it. The following example shows a struct with a `C` representation.
+### The `repr` attribute
-```rust
-#[repr(C)]
-struct ThreeInts {
- first: i16,
- second: i8,
- third: i32
-}
-```
+r[layout.repr.attribute.intro]
+The *`repr` [attribute][attributes]* can change the representation and layout of a type.
-r[layout.repr.align-packed]
-The alignment may be raised or lowered with the `align` and `packed` modifiers
-respectively. They alter the representation specified in the attribute.
-If no representation is specified, the default one is altered.
+> [!EXAMPLE]
+> The following example shows a struct with a `C` representation.
+>
+> ```rust
+> #[repr(C)]
+> struct ThreeInts {
+> first: i16,
+> second: i8,
+> third: i32
+> }
+> ```
-```rust
-// Default representation, alignment lowered to 2.
-#[repr(packed(2))]
-struct PackedStruct {
- first: i16,
- second: i8,
- third: i32
-}
+> [!NOTE]
+> As a consequence of the representation being an attribute on the item, the representation does not depend on generic parameters. Any two types with the same name have the same representation. For example, `Foo` and `Foo` both have the same representation.
-// C representation, alignment raised to 8
-#[repr(C, align(8))]
-struct AlignedStruct {
- first: i16,
- second: i8,
- third: i32
-}
+r[layout.repr.attribute.syntax]
+The syntax for the `repr` attribute is:
+
+```grammar,attributes
+@root ReprAttribute -> `repr` `(` ( Repr (`,` Repr)* `,`? )? `)`
+
+Repr ->
+ `Rust`
+ | `C`
+ | `transparent`
+ | `i8`
+ | `u8`
+ | `i16`
+ | `u16`
+ | `i32`
+ | `u32`
+ | `i64`
+ | `u64`
+ | `i128`
+ | `u128`
+ | `isize`
+ | `usize`
+ | `align` `(` Alignment `)`
+ | `packed` ( `(` Alignment `)` )?
+
+Alignment -> DEC_LITERAL | BIN_LITERAL | OCT_LITERAL | HEX_LITERAL
```
+The values of the `repr` attribute are described in the following sections:
+
+- `Rust` --- [layout.repr.rust]
+- `C` --- [layout.repr.c]
+- `transparent` --- [layout.repr.transparent]
+- Primitive representations --- [layout.repr.primitive]
+- `align` and `packed` modifiers --- [layout.repr.alignment]
+
+If multiple values are specified, then the combination of all the specified representations is used as specified in [layout.repr.attribute.combinations].
+
+r[layout.repr.attribute.allowed-positions]
+The `repr` attribute may only be applied to a [struct], [enum], or [union].
+
> [!NOTE]
-> As a consequence of the representation being an attribute on the item, the representation does not depend on generic parameters. Any two types with the same name have the same representation. For example, `Foo` and `Foo` both have the same representation.
+> There are some restrictions on which `repr` values can be applied to specific kinds of items. For example, the primitive representations can only be applied to enumerations. The sections for each repr value describes their restrictions.
+
+r[layout.repr.attribute.duplicates]
+If the `repr` attribute is specified multiple times on an item, then the combination of all the specified values is used as specified in [layout.repr.attribute.combinations].
+
+r[layout.repr.attribute.combinations]
+Combinations of `repr` values on the same type are handled as follows:
+
+r[layout.repr.attribute.combinations.transparent]
+- `transparent` --- May not be combined with any other value.
+r[layout.repr.attribute.combinations.rust]
+- `Rust` --- May not be combined with primitive representations or `C`.
+r[layout.repr.attribute.combinations.primitive]
+- Multiple primitive representations are not allowed.
+
+r[layout.repr.attribute.combinations.primitive-c]
+- A primitive representation with `C` is described in [layout.repr.primitive-c].
+r[layout.repr.attribute.combinations.primitive-unit-only]
+- A primitive representation with `C` on a [unit-only enum] is not allowed.
+
+r[layout.repr.attribute.combinations.align-packed]
+- `align` and `packed` may not be applied on the same type.
+r[layout.repr.attribute.combinations.align-packed-rust-or-c]
+- `align` and `packed` may only be applied to a type with the `Rust` or `C` representation.
+r[layout.repr.attribute.combinations.align-max]
+- If multiple align values are given, the maximum value is used.
+r[layout.repr.attribute.combinations.packed-min]
+- If multiple packed values are given, the minimum value is used.
+r[layout.repr.attribute.combinations.rust-c-dupe]
+- Duplicate instances of the `Rust` or `C` value are ignored.
r[layout.repr.inter-field]
-The representation of a type can change the padding between fields, but does
-not change the layout of the fields themselves. For example, a struct with a
-`C` representation that contains a struct `Inner` with the `Rust`
-representation will not change the layout of `Inner`.
+The representation of a type can change the padding between fields, but does not change the layout of the fields themselves. For example, a struct with a `C` representation that contains a struct `Inner` with the `Rust` representation will not change the layout of `Inner`.
r[layout.repr.rust]
### The `Rust` Representation
r[layout.repr.rust.intro]
-The `Rust` representation is the default representation for nominal types
-without a `repr` attribute. Using this representation explicitly through a
-`repr` attribute is guaranteed to be the same as omitting the attribute
-entirely.
+The `Rust` representation is the default representation for nominal types without a `repr` attribute. Using this representation explicitly through a `repr` attribute is guaranteed to be the same as omitting the attribute entirely.
r[layout.repr.rust.layout]
-The only data layout guarantees made by this representation are those required
-for soundness. They are:
+The only data layout guarantees made by this representation are those required for soundness. They are:
1. The fields are properly aligned.
2. The fields do not overlap.
3. The alignment of the type is at least the maximum alignment of its fields.
r[layout.repr.rust.alignment]
-Formally, the first guarantee means that the offset of any field is divisible by
-that field's alignment.
+Formally, the first guarantee means that the offset of any field is divisible by that field's alignment.
r[layout.repr.rust.field-storage]
-The second guarantee means that the fields can be
-ordered such that the offset plus the size of any field is less than or equal to
-the offset of the next field in the ordering. The ordering does not have to be
-the same as the order in which the fields are specified in the declaration of
-the type.
+The second guarantee means that the fields can be ordered such that the offset plus the size of any field is less than or equal to the offset of the next field in the ordering. The ordering does not have to be the same as the order in which the fields are specified in the declaration of the type.
-Be aware that the second guarantee does not imply that the fields have distinct
-addresses: zero-sized types may have the same address as other fields in the
-same struct.
+Be aware that the second guarantee does not imply that the fields have distinct addresses: zero-sized types may have the same address as other fields in the same struct.
r[layout.repr.rust.unspecified]
There are no other guarantees of data layout made by this representation.
@@ -234,17 +243,12 @@ r[layout.repr.c]
### The `C` Representation
r[layout.repr.c.intro]
-The `C` representation is designed for dual purposes. One purpose is for
-creating types that are interoperable with the C Language. The second purpose is
-to create types that you can soundly perform operations on that rely on data
-layout such as reinterpreting values as a different type.
+The `C` representation is designed for dual purposes. One purpose is for creating types that are interoperable with the C Language. The second purpose is to create types that you can soundly perform operations on that rely on data layout such as reinterpreting values as a different type.
-Because of this dual purpose, it is possible to create types that are not useful
-for interfacing with the C programming language.
+Because of this dual purpose, it is possible to create types that are not useful for interfacing with the C programming language.
r[layout.repr.c.constraint]
-This representation can be applied to structs, unions, and enums. The exception
-is [zero-variant enums] for which the `C` representation is an error.
+This representation can be applied to structs, unions, and enums. The exception is [zero-variant enums] for which the `C` representation is an error.
r[layout.repr.c.struct]
#### `#[repr(C)]` Structs
@@ -257,14 +261,9 @@ The size and offset of fields is determined by the following algorithm.
Start with a current offset of 0 bytes.
-For each field in declaration order in the struct, first determine the size and
-alignment of the field. If the current offset is not a multiple of the field's
-alignment, then add padding bytes to the current offset until it is a multiple
-of the field's alignment. The offset for the field is what the current offset
-is now. Then increase the current offset by the size of the field.
+For each field in declaration order in the struct, first determine the size and alignment of the field. If the current offset is not a multiple of the field's alignment, then add padding bytes to the current offset until it is a multiple of the field's alignment. The offset for the field is what the current offset is now. Then increase the current offset by the size of the field.
-Finally, the size of the struct is the current offset rounded up to the nearest
-multiple of the struct's alignment.
+Finally, the size of the struct is the current offset rounded up to the nearest multiple of the struct's alignment.
Here is this algorithm described in pseudocode.
@@ -311,13 +310,10 @@ r[layout.repr.c.union]
#### `#[repr(C)]` Unions
r[layout.repr.c.union.intro]
-A union declared with `#[repr(C)]` will have the same size and alignment as an
-equivalent C union declaration in the C language for the target platform.
+A union declared with `#[repr(C)]` will have the same size and alignment as an equivalent C union declaration in the C language for the target platform.
r[layout.repr.c.union.size-align]
-The union will have a size of the maximum size of all of its fields rounded to
-its alignment, and an alignment of the maximum alignment of all of its fields.
-These maximums may come from different fields.
+The union will have a size of the maximum size of all of its fields rounded to its alignment, and an alignment of the maximum alignment of all of its fields. These maximums may come from different fields.
```rust
#[repr(C)]
@@ -344,8 +340,7 @@ assert_eq!(std::mem::align_of::(), 4); // From a
r[layout.repr.c.enum]
#### `#[repr(C)]` Field-less Enums
-For [field-less enums], the `C` representation has the size and alignment of
-the default `enum` size and alignment for the target platform's C ABI.
+For [field-less enums], the `C` representation has the size and alignment of the default `enum` size and alignment for the target platform's C ABI.
> [!NOTE]
> The enum representation in C is implementation defined, so this is really a "best guess". In particular, this may be incorrect when the C code of interest is compiled with certain flags.
@@ -378,7 +373,7 @@ enum MyEnum {
B(f32, u64),
C { x: u32, y: u8 },
D,
- }
+}
// ... this struct.
#[repr(C)]
@@ -426,31 +421,23 @@ r[layout.repr.primitive]
### Primitive representations
r[layout.repr.primitive.intro]
-The *primitive representations* are the representations with the same names as
-the primitive integer types. That is: `u8`, `u16`, `u32`, `u64`, `u128`,
-`usize`, `i8`, `i16`, `i32`, `i64`, `i128`, and `isize`.
+The *primitive representations* are used to change the representation of an enumeration. They have the same names as the primitive integer types. That is: `u8`, `u16`, `u32`, `u64`, `u128`, `usize`, `i8`, `i16`, `i32`, `i64`, `i128`, and `isize`.
+
+r[layout.repr.primitive.enum-only]
+Primitive representations can only be applied to enumerations and have different behavior whether the enum has fields or no fields.
-r[layout.repr.primitive.constraint]
-Primitive representations can only be applied to enumerations and have
-different behavior whether the enum has fields or no fields. It is an error
-for [zero-variant enums] to have a primitive representation. Combining
-two primitive representations together is an error.
+r[layout.repr.primitive.zero-variant]
+It is an error for [zero-variant enums] to have a primitive representation.
r[layout.repr.primitive.enum]
#### Primitive Representation of Field-less Enums
-For [field-less enums], primitive representations set the size and alignment to
-be the same as the primitive type of the same name. For example, a field-less
-enum with a `u8` representation can only have discriminants between 0 and 255
-inclusive.
+For [field-less enums], primitive representations set the size and alignment to be the same as the primitive type of the same name. For example, a field-less enum with a `u8` representation can only have discriminants between 0 and 255 inclusive.
r[layout.repr.primitive.adt]
#### Primitive Representation of Enums With Fields
-The representation of a primitive representation enum is a `repr(C)` union of
-`repr(C)` structs for each variant with a field. The first field of each struct
-in the union is the primitive representation version of the enum with all fields
-removed ("the tag") and the remaining fields are the fields of that variant.
+The representation of a primitive representation enum is a `repr(C)` union of `repr(C)` structs for each variant with a field. The first field of each struct in the union is the primitive representation version of the enum with all fields removed ("the tag") and the remaining fields are the fields of that variant.
> [!NOTE]
> This representation is unchanged if the tag is given its own member in the union, should that make manipulation more clear for you (although to follow the C++ standard the tag member should be wrapped in a `struct`).
@@ -463,7 +450,7 @@ enum MyEnum {
B(f32, u64),
C { x: u32, y: u8 },
D,
- }
+}
// ... this union.
#[repr(C)]
@@ -502,11 +489,7 @@ struct MyVariantD(MyEnumDiscriminant);
r[layout.repr.primitive-c]
#### Combining primitive representations of enums with fields and `#[repr(C)]`
-For enums with fields, it is also possible to combine `repr(C)` and a
-primitive representation (e.g., `repr(C, u8)`). This modifies the [`repr(C)`] by
-changing the representation of the discriminant enum to the chosen primitive
-instead. So, if you chose the `u8` representation, then the discriminant enum
-would have a size and alignment of 1 byte.
+For enums with fields, it is also possible to combine `repr(C)` and a primitive representation (e.g., `repr(C, u8)`). This modifies the [`repr(C)`] by changing the representation of the discriminant enum to the chosen primitive instead. So, if you chose the `u8` representation, then the discriminant enum would have a size and alignment of 1 byte.
The discriminant enum from the example [earlier][`repr(C)`] then becomes:
@@ -527,12 +510,9 @@ enum MyEnumDiscriminant { A, B, C, D }
// ...
```
-For example, with a `repr(C, u8)` enum it is not possible to have 257 unique
-discriminants ("tags") whereas the same enum with only a `repr(C)` attribute
-will compile without any problems.
+For example, with a `repr(C, u8)` enum it is not possible to have 257 unique discriminants ("tags") whereas the same enum with only a `repr(C)` attribute will compile without any problems.
-Using a primitive representation in addition to `repr(C)` can change the size of
-an enum from the `repr(C)` form:
+Using a primitive representation in addition to `repr(C)` can change the size of an enum from the `repr(C)` form:
```rust
#[repr(C)]
@@ -568,48 +548,52 @@ r[layout.repr.alignment]
### The alignment modifiers
r[layout.repr.alignment.intro]
-The `align` and `packed` modifiers can be used to respectively raise or lower
-the alignment of `struct`s and `union`s. `packed` may also alter the padding
-between fields (although it will not alter the padding inside of any field).
-On their own, `align` and `packed` do not provide guarantees about the order
-of fields in the layout of a struct or the layout of an enum variant, although
-they may be combined with representations (such as `C`) which do provide such
-guarantees.
+The `align` and `packed` modifiers can be used to respectively raise or lower the alignment of `struct`s and `union`s. `packed` may also alter the padding between fields (although it will not alter the padding inside of any field).
+
+On their own, `align` and `packed` do not provide guarantees about the order of fields in the layout of a struct or the layout of an enum variant, although they may be combined with representations (such as `C`) which do provide such guarantees.
+
+> [!EXAMPLE]
+> ```rust
+> // Default representation, alignment lowered to 2.
+> #[repr(packed(2))]
+> struct PackedStruct {
+> first: i16,
+> second: i8,
+> third: i32
+> }
+>
+> // C representation, alignment raised to 8
+> #[repr(C, align(8))]
+> struct AlignedStruct {
+> first: i16,
+> second: i8,
+> third: i32
+> }
+> ```
r[layout.repr.alignment.constraint-alignment]
-The alignment is specified as an integer parameter in the form of
-`#[repr(align(x))]` or `#[repr(packed(x))]`. The alignment value must be a
-power of two from 1 up to 229. For `packed`, if no value is given,
-as in `#[repr(packed)]`, then the value is 1.
+The alignment is specified as an integer parameter in the form of `#[repr(align(x))]` or `#[repr(packed(x))]`. The alignment value must be a power of two from 1 up to 229. For `packed`, if no value is given, as in `#[repr(packed)]`, then the value is 1.
r[layout.repr.alignment.align]
-For `align`, if the specified alignment is less than the alignment of the type
-without the `align` modifier, then the alignment is unaffected.
+For `align`, if the specified alignment is less than the alignment of the type without the `align` modifier, then the alignment is unaffected.
r[layout.repr.alignment.packed]
-For `packed`, if the specified alignment is greater than the type's alignment
-without the `packed` modifier, then the alignment and layout is unaffected.
+For `packed`, if the specified alignment is greater than the type's alignment without the `packed` modifier, then the alignment and layout is unaffected.
r[layout.repr.alignment.packed-fields]
-The alignments of each field, for the purpose of positioning fields, is the
-smaller of the specified alignment and the alignment of the field's type.
+The alignments of each field, for the purpose of positioning fields, is the smaller of the specified alignment and the alignment of the field's type.
r[layout.repr.alignment.packed-padding]
-Inter-field padding is guaranteed to be the minimum required in order to
-satisfy each field's (possibly altered) alignment (although note that, on its
-own, `packed` does not provide any guarantee about field ordering). An
-important consequence of these rules is that a type with `#[repr(packed(1))]`
-(or `#[repr(packed)]`) will have no inter-field padding.
-
-r[layout.repr.alignment.constraint-exclusive]
-The `align` and `packed` modifiers cannot be applied on the same type and a
-`packed` type cannot transitively contain another `align`ed type. `align` and
-`packed` may only be applied to the [`Rust`] and [`C`] representations.
-
-r[layout.repr.alignment.enum]
-The `align` modifier can also be applied on an `enum`.
-When it is, the effect on the `enum`'s alignment is the same as if the `enum`
-was wrapped in a newtype `struct` with the same `align` modifier.
+Inter-field padding is guaranteed to be the minimum required in order to satisfy each field's (possibly altered) alignment (although note that, on its own, `packed` does not provide any guarantee about field ordering). An important consequence of these rules is that a type with `#[repr(packed(1))]` (or `#[repr(packed)]`) will have no inter-field padding.
+
+r[layout.repr.alignment.pack-transitive-aligned]
+A `packed` type may not transitively contain another `align`ed type.
+
+r[layout.repr.alignment.packed-enum]
+The `packed` modifier may not be used on an `enum`.
+
+r[layout.repr.alignment.align-enum]
+The `align` modifier may be applied on an `enum`. When it is, the effect on the `enum`'s alignment is the same as if the `enum` was wrapped in a newtype `struct` with the same `align` modifier.
> [!NOTE]
> References to unaligned fields are not allowed because it is [undefined behavior]. When fields are unaligned due to an alignment modifier, consider the following options for using references and dereferences:
@@ -638,23 +622,15 @@ r[layout.repr.transparent]
### The `transparent` Representation
r[layout.repr.transparent.constraint-field]
-The `transparent` representation can only be used on a [`struct`][structs]
-or an [`enum`][enumerations] with a single variant that has:
+The `transparent` representation may only be used on a [`struct`][structs] or an [`enum`][enumerations] with a single variant that has:
+
- any number of fields with size 0 and alignment 1 (e.g. [`PhantomData`]), and
- at most one other field.
r[layout.repr.transparent.layout-abi]
-Structs and enums with this representation have the same layout and ABI
-as the only non-size 0 non-alignment 1 field, if present, or unit otherwise.
-
-This is different than the `C` representation because
-a struct with the `C` representation will always have the ABI of a `C` `struct`
-while, for example, a struct with the `transparent` representation with a
-primitive field will have the ABI of the primitive field.
+Structs and enums with this representation have the same layout and ABI as the only non-size 0 non-alignment 1 field, if present, or unit otherwise.
-r[layout.repr.transparent.constraint-exclusive]
-Because this representation delegates type layout to another type, it cannot be
-used with any other representation.
+This is different than the `C` representation because a struct with the `C` representation will always have the ABI of a `C` `struct` while, for example, a struct with the `transparent` representation with a primitive field will have the ABI of the primitive field.
[`align_of_val`]: std::mem::align_of_val
[`size_of_val`]: std::mem::size_of_val
@@ -676,3 +652,7 @@ used with any other representation.
[structs]: items/structs.md
[`transparent`]: #the-transparent-representation
[`Layout`]: std::alloc::Layout
+[struct]: items/structs.md
+[enum]: items/enumerations.md
+[union]: items/unions.md
+[unit-only enum]: items/enumerations.md#unit-only-enum