@@ -842,11 +842,15 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
842
842
let mut layout_variants = variants
843
843
. iter_enumerated ( )
844
844
. map ( |( i, field_layouts) | {
845
- let mut st = self . univariant (
846
- field_layouts,
847
- repr,
848
- StructKind :: Prefixed ( min_ity. size ( ) , prefix_align) ,
849
- ) ?;
845
+ let uninhabited = field_layouts. iter ( ) . any ( |f| f. is_uninhabited ( ) ) ;
846
+ // We don't need to encode the tag in uninhabited variants in repr(Rust) enums
847
+ let struct_kind = if uninhabited && !repr. inhibit_enum_layout_opt ( ) {
848
+ StructKind :: AlwaysSized
849
+ } else {
850
+ StructKind :: Prefixed ( min_ity. size ( ) , prefix_align)
851
+ } ;
852
+ let mut st = self . univariant ( field_layouts, repr, struct_kind) ?;
853
+
850
854
st. variants = Variants :: Single { index : i, variants : None } ;
851
855
// Find the first field we can't move later
852
856
// to make room for a larger discriminant.
@@ -916,6 +920,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
916
920
let old_ity_size = min_ity. size ( ) ;
917
921
let new_ity_size = ity. size ( ) ;
918
922
for variant in & mut layout_variants {
923
+ // Don't change field offsets of uninhabited variants in repr(Rust) enums,
924
+ // they don't encode the tag and their fields may overlap with the tag.
925
+ if variant. is_uninhabited ( ) && !repr. inhibit_enum_layout_opt ( ) {
926
+ continue ;
927
+ }
919
928
match variant. fields {
920
929
FieldsShape :: Arbitrary { ref mut offsets, .. } => {
921
930
for i in offsets {
@@ -960,6 +969,12 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
960
969
let FieldsShape :: Arbitrary { ref offsets, .. } = layout_variant. fields else {
961
970
panic ! ( "encountered a non-arbitrary layout during enum layout" ) ;
962
971
} ;
972
+ // Don't look in uninhabited variants for repr(Rust) enums, they will never be
973
+ // passed over an ABI so they don't matter for the purpose of determining
974
+ // BackendRepr.
975
+ if layout_variant. is_uninhabited ( ) && !repr. inhibit_enum_layout_opt ( ) {
976
+ continue ;
977
+ }
963
978
// We skip *all* ZST here and later check if we are good in terms of alignment.
964
979
// This lets us handle some cases involving aligned ZST.
965
980
let mut fields = iter:: zip ( field_layouts, offsets) . filter ( |p| !p. 0 . is_zst ( ) ) ;
@@ -1076,6 +1091,43 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
1076
1091
. map ( |v| v. randomization_seed )
1077
1092
. fold ( repr. field_shuffle_seed , |acc, seed| acc. wrapping_add ( seed) ) ;
1078
1093
1094
+ // If all variants are uninhabited, the repr does not inhibit layout optimizations,
1095
+ // and all fields are ZSTs, then the tagged layout will not have room for the tag.
1096
+ // So in this case, we return an uninhabited layout that is big enough and aligned
1097
+ // enough for all variant fields, but do not say it has any fields itself.
1098
+ // Doing this only when the layout is too small to fit the tag gives better error
1099
+ // messages during const-eval in some cases, "constructing invalid value at .<enum-tag>:
1100
+ // encountered an uninhabited enum variant" instead of "constructing invalid value:
1101
+ // encountered a value of uninhabited type".
1102
+ // Note the we only reach this case when there is at least one non-1-aligned ZST field,
1103
+ // since the all-1-ZST case is handled by the "present_variants" check in
1104
+ // `layout_of_struct_or_enum`.
1105
+ if uninhabited && size < tag. size ( & self . cx ) {
1106
+ // The only way for the size to be less than the tag's size is for it to be zero,
1107
+ // which can only occur when the repr does not inhibit layout optimization.
1108
+ debug_assert ! (
1109
+ size == Size :: ZERO ,
1110
+ "size was non-zero but less than tag size: 0 < {size:?} < {:?}" ,
1111
+ tag. size( & self . cx)
1112
+ ) ;
1113
+ debug_assert ! (
1114
+ !repr. inhibit_enum_layout_opt( ) ,
1115
+ "enum size was zero with layout optimizations disabled"
1116
+ ) ;
1117
+ return Ok ( LayoutData {
1118
+ fields : FieldsShape :: Arbitrary { offsets : [ ] . into ( ) , memory_index : [ ] . into ( ) } ,
1119
+ variants : Variants :: Empty { variants : Some ( layout_variants) } ,
1120
+ backend_repr : BackendRepr :: Memory { sized : true } ,
1121
+ largest_niche : None ,
1122
+ uninhabited : true ,
1123
+ align : AbiAlign :: new ( align) ,
1124
+ size,
1125
+ max_repr_align,
1126
+ unadjusted_abi_align,
1127
+ randomization_seed : combined_seed,
1128
+ } ) ;
1129
+ }
1130
+
1079
1131
let tagged_layout = LayoutData {
1080
1132
variants : Variants :: Multiple {
1081
1133
tag,
0 commit comments