@@ -658,12 +658,16 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
658658 let mut align = dl. aggregate_align ;
659659 let mut max_repr_align = repr. align ;
660660 let mut unadjusted_abi_align = align;
661+ let mut inhabited_variants = 0 ;
661662
662663 let mut variant_layouts = variants
663664 . iter_enumerated ( )
664665 . map ( |( j, v) | {
665666 let mut st = self . univariant ( v, repr, StructKind :: AlwaysSized ) . ok ( ) ?;
666667 st. variants = Variants :: Single { index : j, variants : None } ;
668+ if !st. uninhabited {
669+ inhabited_variants += 1 ;
670+ }
667671
668672 align = align. max ( st. align . abi ) ;
669673 max_repr_align = max_repr_align. max ( st. max_repr_align ) ;
@@ -673,14 +677,29 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
673677 } )
674678 . collect :: < Option < IndexVec < VariantIdx , _ > > > ( ) ?;
675679
680+ if inhabited_variants < 2 {
681+ // If there's only one inhabited variant, the no-tag layout will be equivalent to
682+ // what the niched layout would be. Returning `None` here lets us assume there is
683+ // another inhabited variant which simplifies the rest of the layout computation.
684+ return None ;
685+ }
686+
687+ // Choose the largest variant, picking an inhabited variant in a tie
676688 let largest_variant_index = variant_layouts
677689 . iter_enumerated ( )
678- . max_by_key ( |( _i, layout) | layout. size . bytes ( ) )
690+ . max_by_key ( |( _i, layout) | ( layout. size . bytes ( ) , !layout . uninhabited ) )
679691 . map ( |( i, _layout) | i) ?;
680692
693+ if variant_layouts[ largest_variant_index] . uninhabited {
694+ // If the largest variant is uninhabited, then filling its niche would give
695+ // a worse layout than the tagged layout.
696+ return None ;
697+ }
698+
681699 let all_indices = variants. indices ( ) ;
682- let needs_disc =
683- |index : VariantIdx | index != largest_variant_index && !absent ( & variants[ index] ) ;
700+ let needs_disc = |index : VariantIdx | {
701+ index != largest_variant_index && !variant_layouts[ index] . uninhabited
702+ } ;
684703 let niche_variants = all_indices. clone ( ) . find ( |v| needs_disc ( * v) ) . unwrap ( )
685704 ..=all_indices. rev ( ) . find ( |v| needs_disc ( * v) ) . unwrap ( ) ;
686705
@@ -697,6 +716,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
697716 let all_variants_fit = variant_layouts. iter_enumerated_mut ( ) . all ( |( i, layout) | {
698717 if i == largest_variant_index {
699718 return true ;
719+ } else if layout. uninhabited {
720+ // This variant doesn't need to hold space for the niche,
721+ // it just needs to be at-most-as big and aligned as the enum.
722+ return layout. size <= size && layout. align . abi <= align;
700723 }
701724
702725 layout. largest_niche = None ;
@@ -741,14 +764,14 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
741764
742765 let largest_niche = Niche :: from_scalar ( dl, niche_offset, niche_scalar) ;
743766
744- let others_zst = variant_layouts
745- . iter_enumerated ( )
746- . all ( | ( i , layout ) | i == largest_variant_index || layout . size == Size :: ZERO ) ;
767+ let others_zst_or_uninhabited = variant_layouts. iter_enumerated ( ) . all ( | ( i , layout ) | {
768+ i == largest_variant_index || layout . size == Size :: ZERO || layout . uninhabited
769+ } ) ;
747770 let same_size = size == variant_layouts[ largest_variant_index] . size ;
748771 let same_align = align == variant_layouts[ largest_variant_index] . align . abi ;
749772
750773 let uninhabited = variant_layouts. iter ( ) . all ( |v| v. is_uninhabited ( ) ) ;
751- let abi = if same_size && same_align && others_zst {
774+ let abi = if same_size && same_align && others_zst_or_uninhabited {
752775 match variant_layouts[ largest_variant_index] . backend_repr {
753776 // When the total alignment and size match, we can use the
754777 // same ABI as the scalar variant with the reserved niche.
0 commit comments