From 3056194cb7e318031c8f826fe7d859191bff823f Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Mon, 8 Jul 2019 16:53:56 +0200 Subject: [PATCH 1/8] Add examples --- reference/src/layout/structs-and-tuples.md | 37 ++++++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/reference/src/layout/structs-and-tuples.md b/reference/src/layout/structs-and-tuples.md index 652252e9..329e265b 100644 --- a/reference/src/layout/structs-and-tuples.md +++ b/reference/src/layout/structs-and-tuples.md @@ -122,6 +122,7 @@ compiler will not reorder it, to allow for the possibility of unsizing. E.g., `struct Foo { x: u16, y: u32 }` and `struct Foo { x: u16, y: T }` where `T = u32` are not guaranteed to be identical. +<<<<<<< HEAD #### Zero-sized structs For `repr(Rust)`, `repr(packed(N))`, `repr(align(N))`, and `repr(C)` @@ -141,6 +142,28 @@ struct Zst2(Zst1, Zst0); # } ``` +======= +#### Default layout of structs with a single non-zero-sized field + +The default layout of structs with a single non-zero-sized field is the same as +the layout of that field if the alignment requirement of all other fields is 1. + +For example, the layout of: + +```rust +struct SomeStruct(i32, ()); +``` + +is the same as the layout of `i32`, but the layout of: + +```rust +#[repr(align(16))] struct Zst; +struct SomeOtherStruct(i32, Zst); +``` + +is **unspecified**, since there is a zero-sized field in `SomeOtherStruct` with +alignment greater than 1. + #### Unresolved questions During the course of the discussion in [#11] and [#12], various @@ -150,14 +173,14 @@ issue has been opened for further discussion on the repository. This section documents the questions and gives a few light details, but the reader is referred to the issues for further discussion. -**Single-field structs ([#34]).** If you have a struct with single field -(`struct Foo { x: T }`), should we guarantee that the memory layout of -`Foo` is identical to the memory layout of `T` (note that ABI details -around function calls may still draw a distinction, which is why -`#[repr(transparent)]` is needed). What about zero-sized types like -`PhantomData`? +**Zero-sized structs ([#37]).** If you have a struct which -- +transitively -- contains no data of non-zero size, then the size of +that struct will be zero as well. These zero-sized structs appear +frequently as exceptions in other layout considerations (e.g., +single-field structs). An example of such a struct is +`std::marker::PhantomData`. -[#34]: https://github.com/rust-rfcs/unsafe-code-guidelines/issues/34 +[#37]: https://github.com/rust-rfcs/unsafe-code-guidelines/issues/37 **Homogeneous structs ([#36]).** If you have homogeneous structs, where all the `N` fields are of a single type `T`, can we guarantee a mapping to From e6a2db12dbdf2f15797c1a852d8b80cf014751ed Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Thu, 15 Aug 2019 08:30:27 +0200 Subject: [PATCH 2/8] Use 1-ZST terminology --- reference/src/layout/structs-and-tuples.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/reference/src/layout/structs-and-tuples.md b/reference/src/layout/structs-and-tuples.md index 329e265b..23a9ad61 100644 --- a/reference/src/layout/structs-and-tuples.md +++ b/reference/src/layout/structs-and-tuples.md @@ -122,7 +122,6 @@ compiler will not reorder it, to allow for the possibility of unsizing. E.g., `struct Foo { x: u16, y: u32 }` and `struct Foo { x: u16, y: T }` where `T = u32` are not guaranteed to be identical. -<<<<<<< HEAD #### Zero-sized structs For `repr(Rust)`, `repr(packed(N))`, `repr(align(N))`, and `repr(C)` @@ -142,11 +141,10 @@ struct Zst2(Zst1, Zst0); # } ``` -======= #### Default layout of structs with a single non-zero-sized field The default layout of structs with a single non-zero-sized field is the same as -the layout of that field if the alignment requirement of all other fields is 1. +the layout of that field if all other fields are [1-ZST] For example, the layout of: @@ -160,9 +158,7 @@ is the same as the layout of `i32`, but the layout of: #[repr(align(16))] struct Zst; struct SomeOtherStruct(i32, Zst); ``` - -is **unspecified**, since there is a zero-sized field in `SomeOtherStruct` with -alignment greater than 1. +is **unspecified**, since `Zst` is not a [1-ZST]. #### Unresolved questions @@ -423,3 +419,5 @@ proposal (and -- further -- it does not match our existing behavior): thread](https://github.com/rust-rfcs/unsafe-code-guidelines/pull/31#discussion_r224955817)). - Many people would prefer the name ordering to be chosen for "readability" and not optimal layout. + +[1-ZST]: ../glossary.md#zero-sized-type--zst From 8df48e492c6a350ccbfdea5b879958700ebbe76e Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Fri, 16 Aug 2019 17:36:27 +0200 Subject: [PATCH 3/8] Reword --- reference/src/layout/structs-and-tuples.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reference/src/layout/structs-and-tuples.md b/reference/src/layout/structs-and-tuples.md index 23a9ad61..6f23818b 100644 --- a/reference/src/layout/structs-and-tuples.md +++ b/reference/src/layout/structs-and-tuples.md @@ -141,10 +141,10 @@ struct Zst2(Zst1, Zst0); # } ``` -#### Default layout of structs with a single non-zero-sized field +#### Default layout of structs where only a single field is not a 1-ZST -The default layout of structs with a single non-zero-sized field is the same as -the layout of that field if all other fields are [1-ZST] +The default layout of structs where only a single field is not a 1-ZST is the +same as the layout of that non-1-ZST field. For example, the layout of: From bd8e2fe101fbc3239dbb78c75087c539ae30531e Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Fri, 16 Aug 2019 19:20:38 +0200 Subject: [PATCH 4/8] 1-ZST fields are ignored --- reference/src/layout/structs-and-tuples.md | 30 +++++++--------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/reference/src/layout/structs-and-tuples.md b/reference/src/layout/structs-and-tuples.md index 6f23818b..1dd6d70e 100644 --- a/reference/src/layout/structs-and-tuples.md +++ b/reference/src/layout/structs-and-tuples.md @@ -141,24 +141,21 @@ struct Zst2(Zst1, Zst0); # } ``` -#### Default layout of structs where only a single field is not a 1-ZST +#### Structs with 1-ZST fields -The default layout of structs where only a single field is not a 1-ZST is the -same as the layout of that non-1-ZST field. +For the purposes of struct layout [1-ZST] fields are ignored. -For example, the layout of: +For example, ```rust -struct SomeStruct(i32, ()); -``` - -is the same as the layout of `i32`, but the layout of: +type Zst1 = (); +struct S1(i32, Zst1); -```rust -#[repr(align(16))] struct Zst; -struct SomeOtherStruct(i32, Zst); +type Zst2 = [u16; 0]; +struct S2(Zst2, Zst1); ``` -is **unspecified**, since `Zst` is not a [1-ZST]. + +the layout of `S1` is the same as that of `i32` and the layout of `S2` as that of `Zst2`. #### Unresolved questions @@ -169,15 +166,6 @@ issue has been opened for further discussion on the repository. This section documents the questions and gives a few light details, but the reader is referred to the issues for further discussion. -**Zero-sized structs ([#37]).** If you have a struct which -- -transitively -- contains no data of non-zero size, then the size of -that struct will be zero as well. These zero-sized structs appear -frequently as exceptions in other layout considerations (e.g., -single-field structs). An example of such a struct is -`std::marker::PhantomData`. - -[#37]: https://github.com/rust-rfcs/unsafe-code-guidelines/issues/37 - **Homogeneous structs ([#36]).** If you have homogeneous structs, where all the `N` fields are of a single type `T`, can we guarantee a mapping to the memory layout of `[T; N]`? How do we map between the field names From eae3f3c79f80bcc0f8241d244f206c3c96de3d72 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Fri, 16 Aug 2019 19:25:59 +0200 Subject: [PATCH 5/8] Struct with no fields --- reference/src/layout/structs-and-tuples.md | 56 ++++++++++++---------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/reference/src/layout/structs-and-tuples.md b/reference/src/layout/structs-and-tuples.md index 1dd6d70e..aca0ab07 100644 --- a/reference/src/layout/structs-and-tuples.md +++ b/reference/src/layout/structs-and-tuples.md @@ -84,15 +84,17 @@ Structs can have various `#[repr]` flags that influence their layout: ### Default layout ("repr rust") -**The default layout of structs is not specified.** As of this -writing, we have not reached a full consensus on what limitations -should exist on possible field struct layouts, so effectively one must -assume that the compiler can select any layout it likes for each -struct on each compilation, and it is not required to select the same -layout across two compilations. This implies that (among other things) -two structs with the same field types may not be laid out in the same -way (for example, the hypothetical struct representing tuples may be -laid out differently from user-declared structs). +With the exception of the guarantees provided below, **the default layout of +structs is not specified.** + +As of this writing, we have not reached a full consensus on what limitations +should exist on possible field struct layouts, so effectively one must assume +that the compiler can select any layout it likes for each struct on each +compilation, and it is not required to select the same layout across two +compilations. This implies that (among other things) two structs with the same +field types may not be laid out in the same way (for example, the hypothetical +struct representing tuples may be laid out differently from user-declared +structs). Known things that can influence layout (non-exhaustive): @@ -122,6 +124,26 @@ compiler will not reorder it, to allow for the possibility of unsizing. E.g., `struct Foo { x: u16, y: u32 }` and `struct Foo { x: u16, y: T }` where `T = u32` are not guaranteed to be identical. +#### Structs with no fields + +Structs with default layout and no fields are [1-ZST]. + +#### Structs with 1-ZST fields + +For the purposes of struct layout [1-ZST] fields are ignored. + +For example: + +```rust +type Zst1 = (); +struct S1(i32, Zst1); // same layout as i32 + +type Zst2 = [u16; 0]; +struct S2(Zst2, Zst1); // same layout as Zst2 + +struct S3(Zst1); // same layout as Zst1 +``` + #### Zero-sized structs For `repr(Rust)`, `repr(packed(N))`, `repr(align(N))`, and `repr(C)` @@ -141,22 +163,6 @@ struct Zst2(Zst1, Zst0); # } ``` -#### Structs with 1-ZST fields - -For the purposes of struct layout [1-ZST] fields are ignored. - -For example, - -```rust -type Zst1 = (); -struct S1(i32, Zst1); - -type Zst2 = [u16; 0]; -struct S2(Zst2, Zst1); -``` - -the layout of `S1` is the same as that of `i32` and the layout of `S2` as that of `Zst2`. - #### Unresolved questions During the course of the discussion in [#11] and [#12], various From 4442b416d965b722a06865cd1d155e2dc5a81ae5 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Fri, 16 Aug 2019 20:02:14 +0200 Subject: [PATCH 6/8] Add note to ZST struct section --- reference/src/layout/structs-and-tuples.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/reference/src/layout/structs-and-tuples.md b/reference/src/layout/structs-and-tuples.md index aca0ab07..8291e70e 100644 --- a/reference/src/layout/structs-and-tuples.md +++ b/reference/src/layout/structs-and-tuples.md @@ -146,8 +146,10 @@ struct S3(Zst1); // same layout as Zst1 #### Zero-sized structs -For `repr(Rust)`, `repr(packed(N))`, `repr(align(N))`, and `repr(C)` -structs: if all fields of a struct have size 0, then the struct has size 0. +For `repr(Rust)`, `repr(packed(N))`, `repr(align(N))`, and `repr(C)` structs: if +all fields of a struct have size 0, then the struct has size 0. In particular, a +struct with no fields is a ZST, and if it has no repr attribute it is moreover a +1-ZST as it also has no alignment requirements. For example, all these types are zero-sized: From 51f0ec0421812634607f613d6e4332b1ec7589fb Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Fri, 16 Aug 2019 20:21:50 +0200 Subject: [PATCH 7/8] Remove unnecessary section --- reference/src/layout/structs-and-tuples.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/reference/src/layout/structs-and-tuples.md b/reference/src/layout/structs-and-tuples.md index 8291e70e..f9365c07 100644 --- a/reference/src/layout/structs-and-tuples.md +++ b/reference/src/layout/structs-and-tuples.md @@ -124,10 +124,6 @@ compiler will not reorder it, to allow for the possibility of unsizing. E.g., `struct Foo { x: u16, y: u32 }` and `struct Foo { x: u16, y: T }` where `T = u32` are not guaranteed to be identical. -#### Structs with no fields - -Structs with default layout and no fields are [1-ZST]. - #### Structs with 1-ZST fields For the purposes of struct layout [1-ZST] fields are ignored. From 18832710a92ffb7bc4fd088d57c48e86a93e95d8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Aug 2019 14:43:41 +0200 Subject: [PATCH 8/8] rearrange a bit and be more explicit about how our rules interact --- reference/src/layout/structs-and-tuples.md | 52 ++++++++++++++-------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/reference/src/layout/structs-and-tuples.md b/reference/src/layout/structs-and-tuples.md index f9365c07..a4cd97b5 100644 --- a/reference/src/layout/structs-and-tuples.md +++ b/reference/src/layout/structs-and-tuples.md @@ -124,28 +124,11 @@ compiler will not reorder it, to allow for the possibility of unsizing. E.g., `struct Foo { x: u16, y: u32 }` and `struct Foo { x: u16, y: T }` where `T = u32` are not guaranteed to be identical. -#### Structs with 1-ZST fields - -For the purposes of struct layout [1-ZST] fields are ignored. - -For example: - -```rust -type Zst1 = (); -struct S1(i32, Zst1); // same layout as i32 - -type Zst2 = [u16; 0]; -struct S2(Zst2, Zst1); // same layout as Zst2 - -struct S3(Zst1); // same layout as Zst1 -``` - #### Zero-sized structs +[zero-sized structs]: #zero-sized-structs For `repr(Rust)`, `repr(packed(N))`, `repr(align(N))`, and `repr(C)` structs: if -all fields of a struct have size 0, then the struct has size 0. In particular, a -struct with no fields is a ZST, and if it has no repr attribute it is moreover a -1-ZST as it also has no alignment requirements. +all fields of a struct have size 0, then the struct has size 0. For example, all these types are zero-sized: @@ -161,6 +144,37 @@ struct Zst2(Zst1, Zst0); # } ``` +In particular, a struct with no fields is a ZST, and if it has no repr attribute +it is moreover a 1-ZST as it also has no alignment requirements. + +#### Single-field structs +[single-field structs]: #single-field-structs + +A struct with only one field has the same layout as that field. + +#### Structs with 1-ZST fields + +For the purposes of struct layout [1-ZST] fields are ignored. + +In particular, if all but one field are 1-ZST, then the struct is equivalent to +a [single-field struct][single-field structs]. In other words, if all but one +field is a 1-ZST, then the entire struct has the same layout as that one field. + +Similarly, if all fields are 1-ZST, then the struct has the same layout as a +[struct with no fields][zero-sized structs], and is itself a 1-ZST. + +For example: + +```rust +type Zst1 = (); +struct S1(i32, Zst1); // same layout as i32 + +type Zst2 = [u16; 0]; +struct S2(Zst2, Zst1); // same layout as Zst2 + +struct S3(Zst1); // same layout as Zst1 +``` + #### Unresolved questions During the course of the discussion in [#11] and [#12], various