@@ -844,11 +844,15 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
844844 let mut layout_variants = variants
845845 . iter_enumerated ( )
846846 . 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+
852856 st. variants = Variants :: Single { index : i, variants : None } ;
853857 // Find the first field we can't move later
854858 // to make room for a larger discriminant.
@@ -918,6 +922,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
918922 let old_ity_size = min_ity. size ( ) ;
919923 let new_ity_size = ity. size ( ) ;
920924 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+ }
921930 match variant. fields {
922931 FieldsShape :: Arbitrary { ref mut offsets, .. } => {
923932 for i in offsets {
@@ -962,6 +971,12 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
962971 let FieldsShape :: Arbitrary { ref offsets, .. } = layout_variant. fields else {
963972 panic ! ( "encountered a non-arbitrary layout during enum layout" ) ;
964973 } ;
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+ }
965980 // We skip *all* ZST here and later check if we are good in terms of alignment.
966981 // This lets us handle some cases involving aligned ZST.
967982 let mut fields = iter:: zip ( field_layouts, offsets) . filter ( |p| !p. 0 . is_zst ( ) ) ;
@@ -1078,6 +1093,43 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
10781093 . map ( |v| v. randomization_seed )
10791094 . fold ( repr. field_shuffle_seed , |acc, seed| acc. wrapping_add ( seed) ) ;
10801095
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+
10811133 let tagged_layout = LayoutData {
10821134 variants : Variants :: Multiple {
10831135 tag,
0 commit comments