From bea8b9dcac1d3f20c5e5f68ff46ec7328d89b31e Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Thu, 17 Oct 2024 14:29:47 -0400 Subject: [PATCH 1/9] Improve Definition of Type Layout --- src/type-layout.md | 166 ++++++++++++++++++++++++++++----------------- 1 file changed, 105 insertions(+), 61 deletions(-) diff --git a/src/type-layout.md b/src/type-layout.md index 6e91537f7..4bd87deb8 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -140,6 +140,29 @@ r[layout.closure] Closures have no layout guarantees. +## Aggregate Types + +r[layout.aggregate] + +r[layout.aggregate.intro] Aggregate types, `struct`s and `union`s, determine the layout based on its fields, and the [repr][layout.repr] attribute. Each field is categorized by its alignment and size, and an offset within that struct which, by default, is a multiple of its alignment. + +r[layout.aggregate.struct-offsets] The fields of a `struct` have offsets such that none of the fields overlap within the `struct`. + +r[layout.aggregate.struct-size-align] +The size of a `struct` is at least such that each field can be placed within the struct's storage, and the size is a multiple of its alignment. The alignment of a `struct`, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute, is at least the largest alignment of all fields. + +r[layout.aggregate.union-offsets] The fields of a `union` may have any offset within the `union`. In particular, `union` fields are permitted to overlap within the `union`. + +> [!NOTE] +> Typically, union fields are all given offset 0 and are all allocated in the same storage. This is not necessarily guaranteed, however, for [The Rust Representation][layout.repr.rust] + +r[layout.aggregate.union-size-align] The size of a `union` is at least such that the largest field, and the size is a multiple of the alignment. The alignment of a `union`, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute, is at least the largest alignment of all fields. + +r[layout.aggregate.repr] The [`repr`][layout.repr] attribute may restrict the valid offsets for each field, as well as the size and alignment of the aggregate type. By [default][layout.repr.rust], the offsets of fields are unspecified. + +> [!NOTE] +> The choices of the offsets of fields are made per-struct. Two `struct`s or two `union`s with the same fields using [`repr(Rust)`][layout.repr.rust] are not necessarily layed out the same + ## Representations r[layout.repr] @@ -211,33 +234,59 @@ 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. +entirely. + +r[layout.repr.rust.aggregate] The layout of aggregate types with this repr is unspecified, such that the guarantees of all `struct` and `union` types are upheld. + +> [!NOTE] +> `repr(Rust)` does not provide any guarantees other than the default constraints. + +#### `repr(Rust)` Enums + +r[layout.repr.rust.enum] + +r[layout.repr.rust.enum.intro] Like `struct`s and `union`s with the `Rust` representation, `enum`s typically have no guarantees. The fields of individual variants are layed out with the same rules as a `repr(Rust)` struct, and the `enum` contains sufficient information to determine which variant is being represented. + +r[layout.repr.rust.enum.variant-fields] Each field of a variant has an offset within the `enum`, such that no two fields of the same variant overlap, and each field of each variant is aligned, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute. Fields of different variants are allowed to overlap, as though each variant appears within a `union` definition. + +r[layout.repr.rust.enum.size-align] The size of an enum is such that each field of each variant that is not uninhabited can be allocated within the enum at its given offset. The alignment of an enum, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute, is at least the largest alignment of all fields in variants that are inhabited. + +> [!NOTE] +> A Rough approximation of a `repr(Rust)` enum is a `repr(Rust)` union containing `repr(Rust)` structs for each variant, with a discriminant field present in each struct. +> However, there is no guarantee that the discriminant field is any particular size, or exists within the union, nor stores any particular value. +> Several optimizations can also reduce the size of the `enum` beyond what is valid for a union-of-structs layout, even using the `Rust` representation. + +> [!NOTE] +> It is not yet decided whether or not uninhabited variants still need to have storage allocated for their non-zero-sized fields. The documentation here conservatively assumes it is not required. -r[layout.repr.rust.layout] -The only data layout guarantees made by this representation are those required -for soundness. They are: +#### Discriminant Ellision - 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.option] -r[layout.repr.rust.alignment] -Formally, the first guarantee means that the offset of any field is divisible by -that field's alignment. +r[layout.repr.rust.option.intro] Certain `repr(Rust)` enums are specially layed out when used with certain types. This layout process is known as discriminant elision. -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. +r[layout.repr.rust.option.elligible] An `enum` type is a *discriminant elision eligible* enum if: +* It has exactly two variants, +* One variant has exactly one field, known as the *elision candidate field*, and +* The other variant has no fields that have size greater than 0 or alignment greater than 1, known as the *elided variant*. -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. +> [!NOTE] +> The determination of whether an `enum` type is *discriminant elision eligible* applies after mono-morphization. +> In particular, a type like [`core::result::Result`] is *discriminant elision eligible* if either `T` or `E` is instantiated with a 1-ZST type, and [`core::option::Option`] is *discriminant elision eligible* always (due to its `None` variant). -r[layout.repr.rust.unspecified] -There are no other guarantees of data layout made by this representation. +r[layout.repr.rust.option.candidates] The following types are *elision candidate types*: +* [`&U`][type.pointer.reference.shared], if `U` is a `Sized` type +* [`&mut U`][type.pointer.reference.mut], if `U` is a `Sized` type +* [`core::ptr::NonNull`], if `U` is a `Sized` type +* [`alloc::boxed::Box`], if `U` is a `Sized` type +* [`core::num::NonZero`] if `T` is an integer type +* A [function pointer][type.fn-pointer] type +* A `struct`, defined using [`repr(transparent)`][layout.repr.transparent], which has a field that is an *elision candidate*, and all other fields have size 0 and alignment 1. + +r[layout.repr.rust.option.elision] If the *elision candidate field* of a *discriminant elision eligible* `enum` has an *elision candidate type*, then the `enum` has the same layout as that field, except that the value consisting of all `0` bytes represents the *elided variant* of the `enum`. + +> [!NOTE] +> It is valid for this optimization to be performed for types an `enum`s other than those mentioned above, however, it is only guaranteed for these types and `enum`s. ### The `C` Representation @@ -256,15 +305,44 @@ 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. +r[layout.repr.c.aggregate] An aggregate type (`struct` or `union`) with the `C` representation is laid out by each field being given by the smallest valid offset for that field that is ascending in declaration order. That is, for a `union`, each field is at offset `0`, and for a struct, the first field is at offset `0`, then the second is at the next offset aligned to the field type. The size of such an aggregate type is the minimum value valid for the type. + + +r[layout.repr.c.align] An aggregate type with the `C` representation has an alignment equal to the maximum alignment of each of its fields, unless an [alignment modifier][layout.repr.alignment] is present. + +> [!NOTE] +> The layout of unions in particular is maximally compact - the size of a `C` representation `union` is the size of its largest field, rounded up to the alignment of the `union` + +```rust +// Example of union layouts +#[repr(C)] +union Union { + f1: u16, + f2: [u8; 4], +} + +assert_eq!(std::mem::size_of::(), 4); // From f2 +assert_eq!(std::mem::align_of::(), 2); // From f1 + +#[repr(C)] +union SizeRoundedUp { + a: u32, + b: [u16; 3], +} + +assert_eq!(std::mem::size_of::(), 8); // Size of 6 from b, + // rounded up to 8 from + // alignment of a. +assert_eq!(std::mem::align_of::(), 4); // From a +``` + + #### `#[repr(C)]` Structs r[layout.repr.c.struct] -r[layout.repr.c.struct.align] -The alignment of the struct is the alignment of the most-aligned field in it. - r[layout.repr.c.struct.size-field-offset] -The size and offset of fields is determined by the following algorithm. +The specific algorithm for the layout of `repr(C) struct` is given as follows: Start with a current offset of 0 bytes. @@ -315,48 +393,14 @@ struct.size = current_offset + padding_needed_for(current_offset, struct.alignme > [!WARNING] > This pseudocode uses a naive algorithm that ignores overflow issues for the sake of clarity. To perform memory layout computations in actual code, use [`Layout`]. -> Note: This algorithm can produce zero-sized structs. In C, an empty struct +> [!NOTE] +> This algorithm can produce zero-sized structs. In C, an empty struct > declaration like `struct Foo { }` is illegal. However, both gcc and clang > support options to enable such structs, and assign them size zero. C++, in > contrast, gives empty structs a size of 1, unless they are inherited from or > they are fields that have the `[[no_unique_address]]` attribute, in which > case they do not increase the overall size of the struct. -#### `#[repr(C)]` Unions - -r[layout.repr.c.union] - -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. - -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. - -```rust -#[repr(C)] -union Union { - f1: u16, - f2: [u8; 4], -} - -assert_eq!(std::mem::size_of::(), 4); // From f2 -assert_eq!(std::mem::align_of::(), 2); // From f1 - -#[repr(C)] -union SizeRoundedUp { - a: u32, - b: [u16; 3], -} - -assert_eq!(std::mem::size_of::(), 8); // Size of 6 from b, - // rounded up to 8 from - // alignment of a. -assert_eq!(std::mem::align_of::(), 4); // From a -``` - #### `#[repr(C)]` Field-less Enums r[layout.repr.c.enum] From 9b9226cc4cdce4ced536761826e8d7bb02851434 Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Thu, 17 Oct 2024 14:48:03 -0400 Subject: [PATCH 2/9] Temp Commit: Fix broken links pending #1618 --- src/type-layout.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/type-layout.md b/src/type-layout.md index 4bd87deb8..b89671d7c 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -746,3 +746,6 @@ used with any other representation. [structs]: items/structs.md [`transparent`]: #the-transparent-representation [`Layout`]: std::alloc::Layout +[type.pointer.reference.shared]: types/pointer.md#shared-references- +[type.pointer.reference.mut]: types/pointer.md#mutable-references-mut +[type.fn-pointer]: types/function-pointer.md \ No newline at end of file From f67be5cdabb8dcc2252fda6b3039f090df18b87a Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Thu, 17 Oct 2024 14:49:08 -0400 Subject: [PATCH 3/9] Remove extraneous Whitespace --- src/type-layout.md | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/type-layout.md b/src/type-layout.md index b89671d7c..b8f5d9b15 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -146,17 +146,17 @@ r[layout.aggregate] r[layout.aggregate.intro] Aggregate types, `struct`s and `union`s, determine the layout based on its fields, and the [repr][layout.repr] attribute. Each field is categorized by its alignment and size, and an offset within that struct which, by default, is a multiple of its alignment. -r[layout.aggregate.struct-offsets] The fields of a `struct` have offsets such that none of the fields overlap within the `struct`. +r[layout.aggregate.struct-offsets] The fields of a `struct` have offsets such that none of the fields overlap within the `struct`. r[layout.aggregate.struct-size-align] -The size of a `struct` is at least such that each field can be placed within the struct's storage, and the size is a multiple of its alignment. The alignment of a `struct`, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute, is at least the largest alignment of all fields. +The size of a `struct` is at least such that each field can be placed within the struct's storage, and the size is a multiple of its alignment. The alignment of a `struct`, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute, is at least the largest alignment of all fields. r[layout.aggregate.union-offsets] The fields of a `union` may have any offset within the `union`. In particular, `union` fields are permitted to overlap within the `union`. > [!NOTE] > Typically, union fields are all given offset 0 and are all allocated in the same storage. This is not necessarily guaranteed, however, for [The Rust Representation][layout.repr.rust] -r[layout.aggregate.union-size-align] The size of a `union` is at least such that the largest field, and the size is a multiple of the alignment. The alignment of a `union`, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute, is at least the largest alignment of all fields. +r[layout.aggregate.union-size-align] The size of a `union` is at least such that the largest field, and the size is a multiple of the alignment. The alignment of a `union`, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute, is at least the largest alignment of all fields. r[layout.aggregate.repr] The [`repr`][layout.repr] attribute may restrict the valid offsets for each field, as well as the size and alignment of the aggregate type. By [default][layout.repr.rust], the offsets of fields are unspecified. @@ -234,26 +234,26 @@ 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. +entirely. r[layout.repr.rust.aggregate] The layout of aggregate types with this repr is unspecified, such that the guarantees of all `struct` and `union` types are upheld. -> [!NOTE] +> [!NOTE] > `repr(Rust)` does not provide any guarantees other than the default constraints. #### `repr(Rust)` Enums r[layout.repr.rust.enum] -r[layout.repr.rust.enum.intro] Like `struct`s and `union`s with the `Rust` representation, `enum`s typically have no guarantees. The fields of individual variants are layed out with the same rules as a `repr(Rust)` struct, and the `enum` contains sufficient information to determine which variant is being represented. +r[layout.repr.rust.enum.intro] Like `struct`s and `union`s with the `Rust` representation, `enum`s typically have no guarantees. The fields of individual variants are layed out with the same rules as a `repr(Rust)` struct, and the `enum` contains sufficient information to determine which variant is being represented. r[layout.repr.rust.enum.variant-fields] Each field of a variant has an offset within the `enum`, such that no two fields of the same variant overlap, and each field of each variant is aligned, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute. Fields of different variants are allowed to overlap, as though each variant appears within a `union` definition. -r[layout.repr.rust.enum.size-align] The size of an enum is such that each field of each variant that is not uninhabited can be allocated within the enum at its given offset. The alignment of an enum, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute, is at least the largest alignment of all fields in variants that are inhabited. +r[layout.repr.rust.enum.size-align] The size of an enum is such that each field of each variant that is not uninhabited can be allocated within the enum at its given offset. The alignment of an enum, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute, is at least the largest alignment of all fields in variants that are inhabited. > [!NOTE] > A Rough approximation of a `repr(Rust)` enum is a `repr(Rust)` union containing `repr(Rust)` structs for each variant, with a discriminant field present in each struct. -> However, there is no guarantee that the discriminant field is any particular size, or exists within the union, nor stores any particular value. +> However, there is no guarantee that the discriminant field is any particular size, or exists within the union, nor stores any particular value. > Several optimizations can also reduce the size of the `enum` beyond what is valid for a union-of-structs layout, even using the `Rust` representation. > [!NOTE] @@ -263,7 +263,7 @@ r[layout.repr.rust.enum.size-align] The size of an enum is such that each field r[layout.repr.rust.option] -r[layout.repr.rust.option.intro] Certain `repr(Rust)` enums are specially layed out when used with certain types. This layout process is known as discriminant elision. +r[layout.repr.rust.option.intro] Certain `repr(Rust)` enums are specially layed out when used with certain types. This layout process is known as discriminant elision. r[layout.repr.rust.option.elligible] An `enum` type is a *discriminant elision eligible* enum if: * It has exactly two variants, @@ -271,7 +271,7 @@ r[layout.repr.rust.option.elligible] An `enum` type is a *discriminant elision e * The other variant has no fields that have size greater than 0 or alignment greater than 1, known as the *elided variant*. > [!NOTE] -> The determination of whether an `enum` type is *discriminant elision eligible* applies after mono-morphization. +> The determination of whether an `enum` type is *discriminant elision eligible* applies after mono-morphization. > In particular, a type like [`core::result::Result`] is *discriminant elision eligible* if either `T` or `E` is instantiated with a 1-ZST type, and [`core::option::Option`] is *discriminant elision eligible* always (due to its `None` variant). r[layout.repr.rust.option.candidates] The following types are *elision candidate types*: @@ -307,8 +307,7 @@ is [zero-variant enums] for which the `C` representation is an error. r[layout.repr.c.aggregate] An aggregate type (`struct` or `union`) with the `C` representation is laid out by each field being given by the smallest valid offset for that field that is ascending in declaration order. That is, for a `union`, each field is at offset `0`, and for a struct, the first field is at offset `0`, then the second is at the next offset aligned to the field type. The size of such an aggregate type is the minimum value valid for the type. - -r[layout.repr.c.align] An aggregate type with the `C` representation has an alignment equal to the maximum alignment of each of its fields, unless an [alignment modifier][layout.repr.alignment] is present. +r[layout.repr.c.align] An aggregate type with the `C` representation has an alignment equal to the maximum alignment of each of its fields, unless an [alignment modifier][layout.repr.alignment] is present. > [!NOTE] > The layout of unions in particular is maximally compact - the size of a `C` representation `union` is the size of its largest field, rounded up to the alignment of the `union` @@ -336,7 +335,6 @@ assert_eq!(std::mem::size_of::(), 8); // Size of 6 from b, assert_eq!(std::mem::align_of::(), 4); // From a ``` - #### `#[repr(C)]` Structs r[layout.repr.c.struct] From 6e46f6a09a935e56bd1155712aa8d2d3bc5510f4 Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Thu, 17 Oct 2024 14:53:33 -0400 Subject: [PATCH 4/9] Rule-ids need a line break after them. Don't forget them --- src/type-layout.md | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/src/type-layout.md b/src/type-layout.md index b8f5d9b15..2d26a5f2c 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -144,21 +144,26 @@ Closures have no layout guarantees. r[layout.aggregate] -r[layout.aggregate.intro] Aggregate types, `struct`s and `union`s, determine the layout based on its fields, and the [repr][layout.repr] attribute. Each field is categorized by its alignment and size, and an offset within that struct which, by default, is a multiple of its alignment. +r[layout.aggregate.intro] +Aggregate types, `struct`s and `union`s, determine the layout based on its fields, and the [repr][layout.repr] attribute. Each field is categorized by its alignment and size, and an offset within that struct which, by default, is a multiple of its alignment. -r[layout.aggregate.struct-offsets] The fields of a `struct` have offsets such that none of the fields overlap within the `struct`. +r[layout.aggregate.struct-offsets] +The fields of a `struct` have offsets such that none of the fields overlap within the `struct`. r[layout.aggregate.struct-size-align] The size of a `struct` is at least such that each field can be placed within the struct's storage, and the size is a multiple of its alignment. The alignment of a `struct`, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute, is at least the largest alignment of all fields. -r[layout.aggregate.union-offsets] The fields of a `union` may have any offset within the `union`. In particular, `union` fields are permitted to overlap within the `union`. +r[layout.aggregate.union-offsets] +The fields of a `union` may have any offset within the `union`. In particular, `union` fields are permitted to overlap within the `union`. > [!NOTE] > Typically, union fields are all given offset 0 and are all allocated in the same storage. This is not necessarily guaranteed, however, for [The Rust Representation][layout.repr.rust] -r[layout.aggregate.union-size-align] The size of a `union` is at least such that the largest field, and the size is a multiple of the alignment. The alignment of a `union`, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute, is at least the largest alignment of all fields. +r[layout.aggregate.union-size-align] +The size of a `union` is at least such that the largest field, and the size is a multiple of the alignment. The alignment of a `union`, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute, is at least the largest alignment of all fields. -r[layout.aggregate.repr] The [`repr`][layout.repr] attribute may restrict the valid offsets for each field, as well as the size and alignment of the aggregate type. By [default][layout.repr.rust], the offsets of fields are unspecified. +r[layout.aggregate.repr] +The [`repr`][layout.repr] attribute may restrict the valid offsets for each field, as well as the size and alignment of the aggregate type. By [default][layout.repr.rust], the offsets of fields are unspecified. > [!NOTE] > The choices of the offsets of fields are made per-struct. Two `struct`s or two `union`s with the same fields using [`repr(Rust)`][layout.repr.rust] are not necessarily layed out the same @@ -236,7 +241,8 @@ 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.aggregate] The layout of aggregate types with this repr is unspecified, such that the guarantees of all `struct` and `union` types are upheld. +r[layout.repr.rust.aggregate] +The layout of aggregate types with this repr is unspecified, such that the guarantees of all `struct` and `union` types are upheld. > [!NOTE] > `repr(Rust)` does not provide any guarantees other than the default constraints. @@ -245,11 +251,14 @@ r[layout.repr.rust.aggregate] The layout of aggregate types with this repr is un r[layout.repr.rust.enum] -r[layout.repr.rust.enum.intro] Like `struct`s and `union`s with the `Rust` representation, `enum`s typically have no guarantees. The fields of individual variants are layed out with the same rules as a `repr(Rust)` struct, and the `enum` contains sufficient information to determine which variant is being represented. +r[layout.repr.rust.enum.intro] +Like `struct`s and `union`s with the `Rust` representation, `enum`s typically have no guarantees. The fields of individual variants are layed out with the same rules as a `repr(Rust)` struct, and the `enum` contains sufficient information to determine which variant is being represented. -r[layout.repr.rust.enum.variant-fields] Each field of a variant has an offset within the `enum`, such that no two fields of the same variant overlap, and each field of each variant is aligned, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute. Fields of different variants are allowed to overlap, as though each variant appears within a `union` definition. +r[layout.repr.rust.enum.variant-fields] +Each field of a variant has an offset within the `enum`, such that no two fields of the same variant overlap, and each field of each variant is aligned, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute. Fields of different variants are allowed to overlap, as though each variant appears within a `union` definition. -r[layout.repr.rust.enum.size-align] The size of an enum is such that each field of each variant that is not uninhabited can be allocated within the enum at its given offset. The alignment of an enum, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute, is at least the largest alignment of all fields in variants that are inhabited. +r[layout.repr.rust.enum.size-align] +The size of an enum is such that each field of each variant that is not uninhabited can be allocated within the enum at its given offset. The alignment of an enum, unless modified by the [`repr(packed)`][layout.repr.alignment.packed] attribute, is at least the largest alignment of all fields in variants that are inhabited. > [!NOTE] > A Rough approximation of a `repr(Rust)` enum is a `repr(Rust)` union containing `repr(Rust)` structs for each variant, with a discriminant field present in each struct. @@ -263,9 +272,11 @@ r[layout.repr.rust.enum.size-align] The size of an enum is such that each field r[layout.repr.rust.option] -r[layout.repr.rust.option.intro] Certain `repr(Rust)` enums are specially layed out when used with certain types. This layout process is known as discriminant elision. +r[layout.repr.rust.option.intro] +Certain `repr(Rust)` enums are specially layed out when used with certain types. This layout process is known as discriminant elision. -r[layout.repr.rust.option.elligible] An `enum` type is a *discriminant elision eligible* enum if: +r[layout.repr.rust.option.elligible] +An `enum` type is a *discriminant elision eligible* enum if: * It has exactly two variants, * One variant has exactly one field, known as the *elision candidate field*, and * The other variant has no fields that have size greater than 0 or alignment greater than 1, known as the *elided variant*. @@ -274,7 +285,8 @@ r[layout.repr.rust.option.elligible] An `enum` type is a *discriminant elision e > The determination of whether an `enum` type is *discriminant elision eligible* applies after mono-morphization. > In particular, a type like [`core::result::Result`] is *discriminant elision eligible* if either `T` or `E` is instantiated with a 1-ZST type, and [`core::option::Option`] is *discriminant elision eligible* always (due to its `None` variant). -r[layout.repr.rust.option.candidates] The following types are *elision candidate types*: +r[layout.repr.rust.option.candidates] +The following types are *elision candidate types*: * [`&U`][type.pointer.reference.shared], if `U` is a `Sized` type * [`&mut U`][type.pointer.reference.mut], if `U` is a `Sized` type * [`core::ptr::NonNull`], if `U` is a `Sized` type @@ -283,7 +295,8 @@ r[layout.repr.rust.option.candidates] The following types are *elision candidate * A [function pointer][type.fn-pointer] type * A `struct`, defined using [`repr(transparent)`][layout.repr.transparent], which has a field that is an *elision candidate*, and all other fields have size 0 and alignment 1. -r[layout.repr.rust.option.elision] If the *elision candidate field* of a *discriminant elision eligible* `enum` has an *elision candidate type*, then the `enum` has the same layout as that field, except that the value consisting of all `0` bytes represents the *elided variant* of the `enum`. +r[layout.repr.rust.option.elision] +If the *elision candidate field* of a *discriminant elision eligible* `enum` has an *elision candidate type*, then the `enum` has the same layout as that field, except that the value consisting of all `0` bytes represents the *elided variant* of the `enum`. > [!NOTE] > It is valid for this optimization to be performed for types an `enum`s other than those mentioned above, however, it is only guaranteed for these types and `enum`s. @@ -305,9 +318,11 @@ 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. -r[layout.repr.c.aggregate] An aggregate type (`struct` or `union`) with the `C` representation is laid out by each field being given by the smallest valid offset for that field that is ascending in declaration order. That is, for a `union`, each field is at offset `0`, and for a struct, the first field is at offset `0`, then the second is at the next offset aligned to the field type. The size of such an aggregate type is the minimum value valid for the type. +r[layout.repr.c.aggregate] +An aggregate type (`struct` or `union`) with the `C` representation is laid out by each field being given by the smallest valid offset for that field that is ascending in declaration order. That is, for a `union`, each field is at offset `0`, and for a struct, the first field is at offset `0`, then the second is at the next offset aligned to the field type. The size of such an aggregate type is the minimum value valid for the type. -r[layout.repr.c.align] An aggregate type with the `C` representation has an alignment equal to the maximum alignment of each of its fields, unless an [alignment modifier][layout.repr.alignment] is present. +r[layout.repr.c.align] +An aggregate type with the `C` representation has an alignment equal to the maximum alignment of each of its fields, unless an [alignment modifier][layout.repr.alignment] is present. > [!NOTE] > The layout of unions in particular is maximally compact - the size of a `C` representation `union` is the size of its largest field, rounded up to the alignment of the `union` From b469f9779df2cae2144861254ba045bfece72a3d Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Thu, 17 Oct 2024 14:55:30 -0400 Subject: [PATCH 5/9] Fix "file must end with a newline" --- src/type-layout.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/type-layout.md b/src/type-layout.md index 2d26a5f2c..555697d5e 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -761,4 +761,4 @@ used with any other representation. [`Layout`]: std::alloc::Layout [type.pointer.reference.shared]: types/pointer.md#shared-references- [type.pointer.reference.mut]: types/pointer.md#mutable-references-mut -[type.fn-pointer]: types/function-pointer.md \ No newline at end of file +[type.fn-pointer]: types/function-pointer.md From cd8bf7b0cb4dc02975a69d59062f267ce6879dea Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Thu, 17 Oct 2024 14:58:39 -0400 Subject: [PATCH 6/9] Put an anchor for reprc-unions --- src/type-layout.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/type-layout.md b/src/type-layout.md index 555697d5e..faf87a2c8 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -324,6 +324,7 @@ An aggregate type (`struct` or `union`) with the `C` representation is laid out r[layout.repr.c.align] An aggregate type with the `C` representation has an alignment equal to the maximum alignment of each of its fields, unless an [alignment modifier][layout.repr.alignment] is present. + > [!NOTE] > The layout of unions in particular is maximally compact - the size of a `C` representation `union` is the size of its largest field, rounded up to the alignment of the `union` From 76422f17cf74c731d2127252748a3fe2eb28a8ff Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Mon, 21 Oct 2024 12:04:24 -0400 Subject: [PATCH 7/9] Revert "Temp Commit: Fix broken links pending #1618" This reverts commit 9b9226cc4cdce4ced536761826e8d7bb02851434. --- src/type-layout.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/type-layout.md b/src/type-layout.md index 9947115c9..c26ef58db 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -765,6 +765,3 @@ used with any other representation. [structs]: items/structs.md [`transparent`]: #the-transparent-representation [`Layout`]: std::alloc::Layout -[type.pointer.reference.shared]: types/pointer.md#shared-references- -[type.pointer.reference.mut]: types/pointer.md#mutable-references-mut -[type.fn-pointer]: types/function-pointer.md From 91326debe628f21781947589d349e64f2989ed7e Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Fri, 22 Nov 2024 13:08:54 -0500 Subject: [PATCH 8/9] Exempt `UnsafeCell` from `layout.repr.rust.option.candidates` --- src/type-layout.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/type-layout.md b/src/type-layout.md index c26ef58db..152212cc0 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -297,7 +297,7 @@ The following types are *elision candidate types*: * [`alloc::boxed::Box`], if `U` is a `Sized` type * [`core::num::NonZero`] if `T` is an integer type * A [function pointer][type.fn-pointer] type -* A `struct`, defined using [`repr(transparent)`][layout.repr.transparent], which has a field that is an *elision candidate*, and all other fields have size 0 and alignment 1. +* A `struct`, other than [`core::cell::UnsafeCell`], defined using [`repr(transparent)`][layout.repr.transparent], which has a field that is an *elision candidate*, and all other fields have size 0 and alignment 1. r[layout.repr.rust.option.elision] If the *elision candidate field* of a *discriminant elision eligible* `enum` has an *elision candidate type*, then the `enum` has the same layout as that field, except that the value consisting of all `0` bytes represents the *elided variant* of the `enum`. From 1d3a35af1f42445442195245bac075a7cd378dab Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Fri, 22 Nov 2024 13:32:27 -0500 Subject: [PATCH 9/9] Define the alignment of char in type-layout chapter --- src/type-layout.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/type-layout.md b/src/type-layout.md index 152212cc0..6f9292572 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -76,6 +76,9 @@ 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.primitive.align-char] +The alignment of `char` is the same as the alignment of `u32`. + ## Pointers and References Layout r[layout.pointer]