From 8255d2fda6edd33117547596efdfc4a98e2c2a96 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Sat, 22 Jun 2019 16:15:02 +0200 Subject: [PATCH 01/10] Update discriminant-elision optimization on Option-like enums --- reference/src/layout/enums.md | 37 ++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/reference/src/layout/enums.md b/reference/src/layout/enums.md index edc3629c..4c8fe01f 100644 --- a/reference/src/layout/enums.md +++ b/reference/src/layout/enums.md @@ -292,11 +292,15 @@ apply, as described below. #### Discriminant elision on Option-like enums -(Meta-note: The content in this section is not described by any RFC -and is therefore "non-normative".) +(Meta-note: The content in this section is not fully described by any RFC and is +therefore "non-normative". Parts of it were specified in +[rust-lang/rust#60300]. -**Definition.** An **option-like enum** is a 2-variant enum where: +[rust-lang/rust#60300]: https://github.com/rust-lang/rust/pull/60300 +**Definition.** An **option-like enum** is a 2-variant `enum` where: + +- the `enum` has no explicit `#[repr(...)]`, and - one variant has a single field, and - the other variant has no fields (the "unit variant"). @@ -313,13 +317,21 @@ values, which are called **niches**. For example, a value of type `&T` may never be `NULL`, and hence defines a niche consisting of the bitstring `0`. Similarly, the standard library types [`NonZeroU8`] and friends may never be zero, and hence also define the value of `0` -as a niche. (Types that define niche values will say so as part of the -description of their validity invariant, which -- as of this writing --- are the next topic up for discussion in the unsafe code guidelines -process.) +as a niche. [`NonZeroU8`]: https://doc.rust-lang.org/std/num/struct.NonZeroU8.html +The niche values of a type are parts of its validity invariant which, as of this +writing, is the current active discussion topic in the unsafe code guidelines +process. [rust-lang/rust#60300] specifies that the following types have a niche: + +* `&T` +* `&mut T` +* `extern "C" fn` +* `core::num::NonZero*` +* `core::ptr::NonNull` +* `#[repr(transparent)] struct` around one of the types in this list. + **Option-like enums where the payload defines at least one niche value are guaranteed to be represented using the same memory layout as their payload.** This is called **discriminant elision**, as there is no @@ -351,6 +363,17 @@ enum Enum1 { } ``` +**Example.** The following enum definition is **not** option-like, +as it has an explicit `repr` attribute. + +```rust +#[repr(u8)] +enum Enum2 { + Present(T), + Absent1, +} +``` + ## Unresolved questions ### Layout of single variant enums From f014c869bf0cb1516cfe5b77b2cc9c682b3f2983 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Sun, 23 Jun 2019 20:16:55 +0200 Subject: [PATCH 02/10] Fix missing parentheses Co-Authored-By: Ralf Jung --- reference/src/layout/enums.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/src/layout/enums.md b/reference/src/layout/enums.md index 4c8fe01f..92bc04d0 100644 --- a/reference/src/layout/enums.md +++ b/reference/src/layout/enums.md @@ -294,7 +294,7 @@ apply, as described below. (Meta-note: The content in this section is not fully described by any RFC and is therefore "non-normative". Parts of it were specified in -[rust-lang/rust#60300]. +[rust-lang/rust#60300]). [rust-lang/rust#60300]: https://github.com/rust-lang/rust/pull/60300 From 470f1d3a02df7cd4f6868f51112a1ffa6ca5e1fd Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Mon, 24 Jun 2019 10:45:24 +0200 Subject: [PATCH 03/10] Specify that the types at least have one niche --- reference/src/layout/enums.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/reference/src/layout/enums.md b/reference/src/layout/enums.md index 4c8fe01f..5a483a47 100644 --- a/reference/src/layout/enums.md +++ b/reference/src/layout/enums.md @@ -323,7 +323,8 @@ as a niche. The niche values of a type are parts of its validity invariant which, as of this writing, is the current active discussion topic in the unsafe code guidelines -process. [rust-lang/rust#60300] specifies that the following types have a niche: +process. [rust-lang/rust#60300] specifies that the following types have at least +one niche (the all-zeros bit-pattern): * `&T` * `&mut T` From cceb00f6fdee7b6efbbba210edd8c2b2574e0be1 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Mon, 24 Jun 2019 11:52:44 +0200 Subject: [PATCH 04/10] Relate niche to validity invariant --- reference/src/layout/enums.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/reference/src/layout/enums.md b/reference/src/layout/enums.md index 2fe30287..31615354 100644 --- a/reference/src/layout/enums.md +++ b/reference/src/layout/enums.md @@ -321,10 +321,11 @@ as a niche. [`NonZeroU8`]: https://doc.rust-lang.org/std/num/struct.NonZeroU8.html -The niche values of a type are parts of its validity invariant which, as of this -writing, is the current active discussion topic in the unsafe code guidelines -process. [rust-lang/rust#60300] specifies that the following types have at least -one niche (the all-zeros bit-pattern): +The niche values must be disjoint from the values allowed by the validity +invariant. The validity invariant is, as of this writing, is the current active +discussion topic in the unsafe code guidelines process. [rust-lang/rust#60300] +specifies that the following types have at least one niche (the all-zeros +bit-pattern): * `&T` * `&mut T` From 78395f3b47e29a3efdfdc7fb8ca239fe7023aa59 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Mon, 24 Jun 2019 12:24:32 +0200 Subject: [PATCH 05/10] Update reference/src/layout/enums.md Co-Authored-By: Ralf Jung --- reference/src/layout/enums.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/src/layout/enums.md b/reference/src/layout/enums.md index 31615354..0df0be7a 100644 --- a/reference/src/layout/enums.md +++ b/reference/src/layout/enums.md @@ -322,7 +322,7 @@ as a niche. [`NonZeroU8`]: https://doc.rust-lang.org/std/num/struct.NonZeroU8.html The niche values must be disjoint from the values allowed by the validity -invariant. The validity invariant is, as of this writing, is the current active +invariant. The validity invariant is, as of this writing, the current active discussion topic in the unsafe code guidelines process. [rust-lang/rust#60300] specifies that the following types have at least one niche (the all-zeros bit-pattern): From 95a102c7e1ad58550a4b13da34559c4c2c775b38 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Mon, 24 Jun 2019 12:31:57 +0200 Subject: [PATCH 06/10] Define niche in the glossary --- reference/src/glossary.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index 80b0ad37..1adf7da1 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -59,9 +59,17 @@ Moreover, the layout of a type records its *function call ABI* (or just *ABI* fo Note: Originally, *layout* and *representation* were treated as synonyms, and Rust language features like the `#[repr]` attribute reflect this. In this document, *layout* and *representation* are not synonyms. +#### Niche + +Invalid bit-patters that will be used by layout optimizations. + +For example, `&mut T` has at least one niche, the "all zeros" bit-pattern. This +niche is used by layout optimizations like "`enum` discriminant elision" to +guarantee that `Option<&mut T>` has the same size as `&mut T`. + + ### TODO -* *niche* * *tag* * *rvalue* * *lvalue* From 823937c9c529deb1c7e6a6c8ea42b67458eaab39 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Mon, 24 Jun 2019 12:33:58 +0200 Subject: [PATCH 07/10] Fix typo --- reference/src/glossary.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index 1adf7da1..6133d412 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -61,12 +61,17 @@ In this document, *layout* and *representation* are not synonyms. #### Niche -Invalid bit-patters that will be used by layout optimizations. +Invalid bit-patterns that will be used by layout optimizations. For example, `&mut T` has at least one niche, the "all zeros" bit-pattern. This niche is used by layout optimizations like "`enum` discriminant elision" to guarantee that `Option<&mut T>` has the same size as `&mut T`. +While all niches are invalid bit-patterns, not all invalid bit-patterns are +niches. For example, the "all bits uninitialized" is an invalid bit-pattern for +`&mut T`, but this bit-pattern is not used by layout optimizations, and is not a +niche. + ### TODO From 84583e222f0baa204662a9515e7ed242197752f9 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 25 Jun 2019 13:52:09 +0200 Subject: [PATCH 08/10] Update reference/src/glossary.md Co-Authored-By: Ralf Jung --- reference/src/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index 6133d412..01b974a6 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -61,7 +61,7 @@ In this document, *layout* and *representation* are not synonyms. #### Niche -Invalid bit-patterns that will be used by layout optimizations. +The *niche* of a type determines invalid bit-patterns that will be used by layout optimizations. For example, `&mut T` has at least one niche, the "all zeros" bit-pattern. This niche is used by layout optimizations like "`enum` discriminant elision" to From ba1f1168cc4c418403353cc85f12a0f77339a44f Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 25 Jun 2019 13:52:16 +0200 Subject: [PATCH 09/10] Update reference/src/glossary.md Co-Authored-By: Ralf Jung --- reference/src/glossary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index 01b974a6..17fa6aab 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -69,7 +69,7 @@ guarantee that `Option<&mut T>` has the same size as `&mut T`. While all niches are invalid bit-patterns, not all invalid bit-patterns are niches. For example, the "all bits uninitialized" is an invalid bit-pattern for -`&mut T`, but this bit-pattern is not used by layout optimizations, and is not a +`&mut T`, but this bit-pattern cannot be used by layout optimizations, and is not a niche. From aa0f61257766042699abbc3a0fd9fff4d4fc0651 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 25 Jun 2019 13:56:01 +0200 Subject: [PATCH 10/10] Hyperlink niche and discriminant-elision optimization --- reference/src/glossary.md | 3 ++- reference/src/layout/enums.md | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/reference/src/glossary.md b/reference/src/glossary.md index 17fa6aab..3b9cf4f7 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -64,7 +64,8 @@ In this document, *layout* and *representation* are not synonyms. The *niche* of a type determines invalid bit-patterns that will be used by layout optimizations. For example, `&mut T` has at least one niche, the "all zeros" bit-pattern. This -niche is used by layout optimizations like "`enum` discriminant elision" to +niche is used by layout optimizations like ["`enum` discriminant +elision"](layout/enums.html#discriminant-elision-on-option-like-enums) to guarantee that `Option<&mut T>` has the same size as `&mut T`. While all niches are invalid bit-patterns, not all invalid bit-patterns are diff --git a/reference/src/layout/enums.md b/reference/src/layout/enums.md index 0df0be7a..286c1546 100644 --- a/reference/src/layout/enums.md +++ b/reference/src/layout/enums.md @@ -313,18 +313,18 @@ field which it contains; in the case of `Option`, the payload has type `T`. **Definition.** In some cases, the payload type may contain illegal -values, which are called **niches**. For example, a value of type `&T` -may never be `NULL`, and hence defines a niche consisting of the +values, which are called **[niches][niche]**. For example, a value of type `&T` +may never be `NULL`, and hence defines a [niche] consisting of the bitstring `0`. Similarly, the standard library types [`NonZeroU8`] and friends may never be zero, and hence also define the value of `0` -as a niche. +as a [niche]. [`NonZeroU8`]: https://doc.rust-lang.org/std/num/struct.NonZeroU8.html -The niche values must be disjoint from the values allowed by the validity +The [niche] values must be disjoint from the values allowed by the validity invariant. The validity invariant is, as of this writing, the current active discussion topic in the unsafe code guidelines process. [rust-lang/rust#60300] -specifies that the following types have at least one niche (the all-zeros +specifies that the following types have at least one [niche] (the all-zeros bit-pattern): * `&T` @@ -334,15 +334,15 @@ bit-pattern): * `core::ptr::NonNull` * `#[repr(transparent)] struct` around one of the types in this list. -**Option-like enums where the payload defines at least one niche value +**Option-like enums where the payload defines at least one [niche] value are guaranteed to be represented using the same memory layout as their payload.** This is called **discriminant elision**, as there is no -explicit discriminant value stored anywhere. Instead, niche values are +explicit discriminant value stored anywhere. Instead, [niche] values are used to represent the unit variant. The most common example is that `Option<&u8>` can be represented as an nullable `&u8` reference -- the `None` variant is then represented -using the niche value zero. This is because a valid `&u8` value can +using the [niche] value zero. This is because a valid `&u8` value can never be zero, so if we see a zero value, we know that this must be `None` variant. @@ -376,6 +376,8 @@ enum Enum2 { } ``` +[niche]: ../glossary.html#niche + ## Unresolved questions ### Layout of single variant enums