@@ -378,90 +378,72 @@ enum Enum2<T> {
378
378
379
379
[niche]: ../glossary.html#niche
380
380
381
- ## Unresolved questions
382
-
383
381
### Layout of single variant enums
384
382
385
- [Issue #79 .](https:// github.com/rust-rfcs/unsafe-code-guidelines/issues/79)
386
-
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.
383
+ **Single variant data-carrying*** enums without a `repr()` annotation have the
384
+ same layout as the variant field. **Single variant fieldless** enums have the
385
+ same layout as a unit struct .
394
386
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 ) ):
387
+ Here:
400
388
401
389
``` rust
402
- struct SomeStruct ;
403
- enum SomeEnum {
404
- SomeVariant ,
405
- }
406
-
390
+ # use std :: mem :: {size_of, align_of};
391
+ struct UnitStruct ;
392
+ enum SingleVariantFieldless { FieldlessVariant }
407
393
# 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 ));
394
+ assert_eq! (size_of :: <SingleVariantFieldless >(), size_of :: <UnitStruct >());
395
+ assert_eq! (align_of :: <SingleVariantFieldless >(), align_of :: <UnitStruct >());
396
+ // assert_eq!(call_abi_of::<SingleVariantFieldless>(), call_abi_of::<UnitStruct>());
397
+ // assert_eq!(niches_of::<SingleVariantFieldless>(), niches_of::<UnitStruct>());
417
398
# }
418
399
```
419
400
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)):
401
+ the single-variant fieldless enum ` SingleVariantFieldless ` has the same layout
402
+ as ` UnitStruct ` .
403
+
404
+ Here:
423
405
424
406
``` rust
407
+ # use std :: mem :: {size_of, align_of};
425
408
struct SomeStruct { x : u32 }
426
- enum SomeEnum {
427
- SomeVariant { x: u32 } ,
409
+ enum SingleVariantDataCarrying {
410
+ DataCarryingVariant ( SomeStruct ) ,
428
411
}
429
-
430
412
# 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));
440
- }
413
+ # assert_eq! (size_of :: <SingleVariantDataCarrying >(), size_of :: <SomeStruct >());
414
+ # assert_eq! (align_of :: <SingleVariantDataCarrying >(), align_of :: <SomeStruct >());
415
+ # }
441
416
```
442
417
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 ) ):
418
+ the single-variant data-carrying enum ` SingleVariantDataCarrying ` has the same
419
+ layout as ` SomeStruct ` .
420
+
421
+ ### Layout of multi-variant enums with one inhabited variant
422
+
423
+ The layout of ** multi-variant** enums with ** one inhabited variant** is the same
424
+ as that of the single-variant enum containing that same inhabited variant.
425
+
426
+ Here:
447
427
448
428
``` rust
449
- # enum Void { }
429
+ # use std :: mem :: {size_of, align_of};
450
430
struct SomeStruct { x : u32 }
451
- enum SomeEnum {
452
- SomeVariant { x : u32 },
453
- UninhabitedVariant { y : Void },
431
+ enum SingleVariantDataCarrying {
432
+ DataCarryingVariant (SomeStruct ),
433
+ }
434
+ enum Void0 {}
435
+ enum Void1 {}
436
+ enum MultiVariantSingleHabited {
437
+ DataCarryingVariant (SomeStruct ),
438
+ Uninhabited0 (Void0 ),
439
+ Uninhabited1 (Void1 ),
454
440
}
455
-
456
441
# fn main () {
457
442
# 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 ));
443
+ # assert_eq! (size_of :: <SingleVariantDataCarrying >(), size_of :: <MultiVariantSingleHabited >());
444
+ # assert_eq! (align_of :: <SingleVariantDataCarrying >(), align_of :: <MultiVariantSingleHabited >());
466
445
# }
467
446
```
447
+
448
+ the ` MultiVariantSingleHabited ` enum has the same layout as
449
+ ` SingleVariantDataCarrying ` .
0 commit comments