Skip to content

Commit 2bda4cb

Browse files
authored
Merge pull request #159 from gnzlbg/resolve_enum_layout
Resolve layout of single variant enums
2 parents 88a22cf + bac4066 commit 2bda4cb

File tree

1 file changed

+20
-79
lines changed

1 file changed

+20
-79
lines changed

Diff for: reference/src/layout/enums.md

+20-79
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ As in C, discriminant values that are not specified are defined as
4646
either 0 (for the first variant) or as one more than the prior
4747
variant.
4848

49-
**Data-carrying enums.** Enums whose variants have fields are called
50-
"data-carrying" enums. Note that for the purposes of this definition,
51-
it is not relevant whether those fields are zero-sized. Therefore this
52-
enum is considered "data-carrying":
49+
**Data-carrying enums.** Enums with at least one variant with fields are called
50+
"data-carrying" enums. Note that for the purposes of this definition, it is not
51+
relevant whether the variant fields are zero-sized. Therefore this enum is
52+
considered "data-carrying":
5353

5454
```rust
5555
enum Foo {
@@ -378,90 +378,31 @@ enum Enum2<T> {
378378

379379
[niche]: ../glossary.html#niche
380380

381-
## Unresolved questions
382-
383-
### Layout of single variant enums
381+
### Layout of enums with a single variant
384382

385-
[Issue #79.](https://github.com/rust-rfcs/unsafe-code-guidelines/issues/79)
383+
> **NOTE**: the guarantees in this section have not been approved by an RFC process.
386384

387-
Enums that contain a **single variant** and which do not have an
388-
explicit `#[repr]` annotation are an important special case. Since
389-
there is only a single variant, the enum must be instantiated with
390-
that variant, which means that the enum is in fact equivalent to a
391-
struct. The question then is to what extent we should **guarantee**
392-
that the two share an equivalent layout, and also how to define the
393-
interaction with uninhabited types.
385+
**Data-carrying** enums with a single variant without a `repr()` annotation have
386+
the same layout as the variant field. **Fieldless** enums with a single variant
387+
have the same layout as a unit struct.
394388

395-
As presently implemented, the compiler will use the same layout for
396-
structs and for single variant enums (as long as they do not have a
397-
`#[repr]` annotation that overrides that choice). So, for example, the
398-
struct `SomeStruct` and the enum `SomeEnum` would have an equivalent
399-
layout ([playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=3697ac684c3d021892694956df957653)):
389+
For example, here:
400390

401391
```rust
402-
struct SomeStruct;
403-
enum SomeEnum {
404-
SomeVariant,
405-
}
392+
struct UnitStruct;
393+
enum FieldlessSingleVariant { FieldlessVariant }
406394

407-
# fn main() {
408-
# use std::mem;
409-
let x = SomeStruct;
410-
let y = SomeEnum::SomeVariant;
411-
assert_eq!(
412-
mem::size_of_val(&x),
413-
mem::size_of_val(&y),
414-
"types have different sizes",
415-
);
416-
println!("types both have size {}", std::mem::size_of_val(&x));
417-
# }
418-
```
419-
420-
Similarly, the struct `SomeStruct` and the enum `SomeVariant` in this
421-
example would also be equivalent in their layout
422-
([playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=924724764419f846c788a8763da45992)):
423-
424-
```rust
425395
struct SomeStruct { x: u32 }
426-
enum SomeEnum {
427-
SomeVariant { x: u32 },
428-
}
429-
430-
# fn main() {
431-
# use std::mem;
432-
let x = SomeStruct { x: 22 };
433-
let y = SomeEnum::SomeVariant { x: 22 };
434-
assert_eq!(
435-
mem::size_of_val(&x),
436-
mem::size_of_val(&y),
437-
"types have different sizes",
438-
);
439-
println!("types both have size {}", mem::size_of_val(&x));
396+
enum DataCarryingSingleVariant {
397+
DataCarryingVariant(SomeStruct),
440398
}
441399
```
442400

443-
In fact, the compiler will use this optimized layout even for enums
444-
that define multiple variants, as long as all but one of the variants
445-
is uninhabited
446-
([playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=3cc1484c5b91097f3dc2015b7c207a0e)):
401+
* `FieldSingleVariant` has the same layout as `UnitStruct`,
402+
* `DataCarryingSingleVariant` has the same layout as `SomeStruct`.
447403

448-
```rust
449-
# enum Void { }
450-
struct SomeStruct { x: u32 }
451-
enum SomeEnum {
452-
SomeVariant { x: u32 },
453-
UninhabitedVariant { y: Void },
454-
}
404+
## Unresolved questions
455405

456-
# fn main() {
457-
# use std::mem;
458-
let x = SomeStruct { x: 22 };
459-
let y = SomeEnum::SomeVariant { x: 22 };
460-
assert_eq!(
461-
mem::size_of_val(&x),
462-
mem::size_of_val(&y),
463-
"types have different sizes",
464-
);
465-
println!("types both have size {}", mem::size_of_val(&x));
466-
# }
467-
```
406+
See [Issue #79.](https://github.com/rust-rfcs/unsafe-code-guidelines/issues/79):
407+
408+
* Layout of multi-variant enums where only one variant is inhabited.

0 commit comments

Comments
 (0)