Skip to content

Commit 1c44b54

Browse files
authored
Merge pull request #149 from gnzlbg/nicheopt
Update discriminant-elision optimization on Option-like enums
2 parents acd2339 + aa0f612 commit 1c44b54

File tree

2 files changed

+54
-13
lines changed

2 files changed

+54
-13
lines changed

reference/src/glossary.md

+15-1
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,23 @@ Moreover, the layout of a type records its *function call ABI* (or just *ABI* fo
5959
Note: Originally, *layout* and *representation* were treated as synonyms, and Rust language features like the `#[repr]` attribute reflect this.
6060
In this document, *layout* and *representation* are not synonyms.
6161

62+
#### Niche
63+
64+
The *niche* of a type determines invalid bit-patterns that will be used by layout optimizations.
65+
66+
For example, `&mut T` has at least one niche, the "all zeros" bit-pattern. This
67+
niche is used by layout optimizations like ["`enum` discriminant
68+
elision"](layout/enums.html#discriminant-elision-on-option-like-enums) to
69+
guarantee that `Option<&mut T>` has the same size as `&mut T`.
70+
71+
While all niches are invalid bit-patterns, not all invalid bit-patterns are
72+
niches. For example, the "all bits uninitialized" is an invalid bit-pattern for
73+
`&mut T`, but this bit-pattern cannot be used by layout optimizations, and is not a
74+
niche.
75+
76+
6277
### TODO
6378

64-
* *niche*
6579
* *tag*
6680
* *rvalue*
6781
* *lvalue*

reference/src/layout/enums.md

+39-12
Original file line numberDiff line numberDiff line change
@@ -292,11 +292,15 @@ apply, as described below.
292292
293293
#### Discriminant elision on Option-like enums
294294
295-
(Meta-note: The content in this section is not described by any RFC
296-
and is therefore "non-normative".)
295+
(Meta-note: The content in this section is not fully described by any RFC and is
296+
therefore "non-normative". Parts of it were specified in
297+
[rust-lang/rust#60300]).
297298
298-
**Definition.** An **option-like enum** is a 2-variant enum where:
299+
[rust-lang/rust#60300]: https://github.com/rust-lang/rust/pull/60300
299300
301+
**Definition.** An **option-like enum** is a 2-variant `enum` where:
302+
303+
- the `enum` has no explicit `#[repr(...)]`, and
300304
- one variant has a single field, and
301305
- the other variant has no fields (the "unit variant").
302306
@@ -309,26 +313,36 @@ field which it contains; in the case of `Option<T>`, the payload has
309313
type `T`.
310314
311315
**Definition.** In some cases, the payload type may contain illegal
312-
values, which are called **niches**. For example, a value of type `&T`
313-
may never be `NULL`, and hence defines a niche consisting of the
316+
values, which are called **[niches][niche]**. For example, a value of type `&T`
317+
may never be `NULL`, and hence defines a [niche] consisting of the
314318
bitstring `0`. Similarly, the standard library types [`NonZeroU8`]
315319
and friends may never be zero, and hence also define the value of `0`
316-
as a niche. (Types that define niche values will say so as part of the
317-
description of their validity invariant, which -- as of this writing
318-
-- are the next topic up for discussion in the unsafe code guidelines
319-
process.)
320+
as a [niche].
320321
321322
[`NonZeroU8`]: https://doc.rust-lang.org/std/num/struct.NonZeroU8.html
322323
323-
**Option-like enums where the payload defines at least one niche value
324+
The [niche] values must be disjoint from the values allowed by the validity
325+
invariant. The validity invariant is, as of this writing, the current active
326+
discussion topic in the unsafe code guidelines process. [rust-lang/rust#60300]
327+
specifies that the following types have at least one [niche] (the all-zeros
328+
bit-pattern):
329+
330+
* `&T`
331+
* `&mut T`
332+
* `extern "C" fn`
333+
* `core::num::NonZero*`
334+
* `core::ptr::NonNull<T>`
335+
* `#[repr(transparent)] struct` around one of the types in this list.
336+
337+
**Option-like enums where the payload defines at least one [niche] value
324338
are guaranteed to be represented using the same memory layout as their
325339
payload.** This is called **discriminant elision**, as there is no
326-
explicit discriminant value stored anywhere. Instead, niche values are
340+
explicit discriminant value stored anywhere. Instead, [niche] values are
327341
used to represent the unit variant.
328342
329343
The most common example is that `Option<&u8>` can be represented as an
330344
nullable `&u8` reference -- the `None` variant is then represented
331-
using the niche value zero. This is because a valid `&u8` value can
345+
using the [niche] value zero. This is because a valid `&u8` value can
332346
never be zero, so if we see a zero value, we know that this must be
333347
`None` variant.
334348
@@ -351,6 +365,19 @@ enum Enum1<T> {
351365
}
352366
```
353367

368+
**Example.** The following enum definition is **not** option-like,
369+
as it has an explicit `repr` attribute.
370+
371+
```rust
372+
#[repr(u8)]
373+
enum Enum2<T> {
374+
Present(T),
375+
Absent1,
376+
}
377+
```
378+
379+
[niche]: ../glossary.html#niche
380+
354381
## Unresolved questions
355382

356383
### Layout of single variant enums

0 commit comments

Comments
 (0)