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