From 79e123a93c2369240e75f02bb1911a8ea55dda78 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 27 Jun 2025 08:48:05 -0700 Subject: [PATCH 1/7] Rework the repr attribute intro to use the template --- src/type-layout.md | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/type-layout.md b/src/type-layout.md index 7f946ba791..b3e67983bf 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -118,16 +118,22 @@ 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. + +> [!EXAMPLE] +> The following example shows a struct with a `C` representation. +> +> ```rust +> #[repr(C)] +> struct ThreeInts { +> first: i16, +> second: i8, +> third: i32 +> } +> ``` 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. From b05e0c31775d3d797be9c97bec31ea33e977f8a9 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 27 Jun 2025 08:50:25 -0700 Subject: [PATCH 2/7] Move the generic repr note to the intro I can't really think of a good place to put this, but it didn't really fit with the rule it currently was in. --- src/type-layout.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/type-layout.md b/src/type-layout.md index b3e67983bf..a0ddf89410 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -135,6 +135,9 @@ The *`repr` [attribute][attributes]* can change the representation and layout of > } > ``` +> [!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. + 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. @@ -156,9 +159,6 @@ struct AlignedStruct { } ``` -> [!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. - 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`. From 28dce48418a4abffa8aaa4acdc9f54f7acf6a753 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 27 Jun 2025 08:53:52 -0700 Subject: [PATCH 3/7] Remove layout.repr.align-packed This more or less repeats what is already said in layout.repr.alignment.intro where it explains that they are modifiers that affect a representation. --- src/type-layout.md | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/type-layout.md b/src/type-layout.md index a0ddf89410..9bb4b6b1d2 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -138,26 +138,8 @@ The *`repr` [attribute][attributes]* can change the representation and layout of > [!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. -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. -```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.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`. @@ -487,6 +469,25 @@ r[layout.repr.alignment] 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. +> [!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. From c6f41ac30df09916b6a33589bd50ed87a66938d2 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 27 Jun 2025 14:12:38 -0700 Subject: [PATCH 4/7] Drive-by whitespace fix --- src/type-layout.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/type-layout.md b/src/type-layout.md index 9bb4b6b1d2..e9317cb6b9 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -301,7 +301,7 @@ enum MyEnum { B(f32, u64), C { x: u32, y: u8 }, D, - } +} // ... this struct. #[repr(C)] @@ -372,7 +372,7 @@ enum MyEnum { B(f32, u64), C { x: u32, y: u8 }, D, - } +} // ... this union. #[repr(C)] @@ -537,6 +537,7 @@ r[layout.repr.transparent] 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: + - any number of fields with size 0 and alignment 1 (e.g. [`PhantomData`]), and - at most one other field. From cb6ecf1e3e803f952e75b55004d02289d45a6b21 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 27 Jun 2025 14:16:21 -0700 Subject: [PATCH 5/7] Add repr attribute template, and add combination rules This consolidates the rules for how repr values can be combined. This adds a few previously undocumented combinations, and I think all permutations should now be covered. --- src/type-layout.md | 103 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 91 insertions(+), 12 deletions(-) diff --git a/src/type-layout.md b/src/type-layout.md index e9317cb6b9..20ae34c3d4 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -138,8 +138,78 @@ The *`repr` [attribute][attributes]* can change the representation and layout of > [!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. +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] +> 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`. @@ -346,10 +416,13 @@ 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.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.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.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 @@ -467,7 +540,9 @@ 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 @@ -503,11 +578,14 @@ The alignments of each field, for the purpose of positioning fields, is the smal 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.pack-transitive-aligned] +A `packed` type may not transitively contain another `align`ed type. -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. +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: @@ -536,7 +614,7 @@ 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. @@ -546,9 +624,6 @@ Structs and enums with this representation have the same layout and ABI as the o 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. -r[layout.repr.transparent.constraint-exclusive] -Because this representation delegates type layout to another type, it cannot be used with any other representation. - [`align_of_val`]: std::mem::align_of_val [`size_of_val`]: std::mem::size_of_val [`align_of`]: std::mem::align_of @@ -568,3 +643,7 @@ Because this representation delegates type layout to another type, it cannot be [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 From 23b2927dfd3e7f6ff2f1eef778eeeb9f84f62c0f Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 7 Oct 2025 14:04:50 -0700 Subject: [PATCH 6/7] Update repr for updated attribute template --- src/type-layout.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/type-layout.md b/src/type-layout.md index 20ae34c3d4..23cb97fb5a 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -117,6 +117,7 @@ The possible representations for a type are: - The [primitive representations] - [`transparent`] + r[layout.repr.attribute] ### The `repr` attribute From 2ca637e17a0e482ed1c0fe7b6d204c4daaf8e416 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 15 Dec 2025 08:52:33 -0800 Subject: [PATCH 7/7] Add trailing comma to match common style Co-authored-by: Tshepang Mbambo --- src/type-layout.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/type-layout.md b/src/type-layout.md index 23cb97fb5a..92647c2821 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -132,7 +132,7 @@ The *`repr` [attribute][attributes]* can change the representation and layout of > struct ThreeInts { > first: i16, > second: i8, -> third: i32 +> third: i32, > } > ``` @@ -552,7 +552,7 @@ On their own, `align` and `packed` do not provide guarantees about the order of > struct PackedStruct { > first: i16, > second: i8, -> third: i32 +> third: i32, > } > > // C representation, alignment raised to 8 @@ -560,7 +560,7 @@ On their own, `align` and `packed` do not provide guarantees about the order of > struct AlignedStruct { > first: i16, > second: i8, -> third: i32 +> third: i32, > } > ```