@@ -842,11 +842,15 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
842842 let mut layout_variants = variants
843843 . iter_enumerated ( )
844844 . 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+
850854 st. variants = Variants :: Single { index : i, variants : None } ;
851855 // Find the first field we can't move later
852856 // to make room for a larger discriminant.
@@ -916,6 +920,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
916920 let old_ity_size = min_ity. size ( ) ;
917921 let new_ity_size = ity. size ( ) ;
918922 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+ }
919928 match variant. fields {
920929 FieldsShape :: Arbitrary { ref mut offsets, .. } => {
921930 for i in offsets {
@@ -960,6 +969,12 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
960969 let FieldsShape :: Arbitrary { ref offsets, .. } = layout_variant. fields else {
961970 panic ! ( "encountered a non-arbitrary layout during enum layout" ) ;
962971 } ;
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+ }
963978 // We skip *all* ZST here and later check if we are good in terms of alignment.
964979 // This lets us handle some cases involving aligned ZST.
965980 let mut fields = iter:: zip ( field_layouts, offsets) . filter ( |p| !p. 0 . is_zst ( ) ) ;
@@ -1076,6 +1091,43 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
10761091 . map ( |v| v. randomization_seed )
10771092 . fold ( repr. field_shuffle_seed , |acc, seed| acc. wrapping_add ( seed) ) ;
10781093
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+
10791131 let tagged_layout = LayoutData {
10801132 variants : Variants :: Multiple {
10811133 tag,
0 commit comments