@@ -660,12 +660,16 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
660660 let mut align = dl. aggregate_align ;
661661 let mut max_repr_align = repr. align ;
662662 let mut unadjusted_abi_align = align. abi ;
663+ let mut inhabited_variants = 0 ;
663664
664665 let mut variant_layouts = variants
665666 . iter_enumerated ( )
666667 . map ( |( j, v) | {
667668 let mut st = self . univariant ( v, repr, StructKind :: AlwaysSized ) . ok ( ) ?;
668669 st. variants = Variants :: Single { index : j, variants : None } ;
670+ if !st. uninhabited {
671+ inhabited_variants += 1 ;
672+ }
669673
670674 align = align. max ( st. align ) ;
671675 max_repr_align = max_repr_align. max ( st. max_repr_align ) ;
@@ -675,14 +679,29 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
675679 } )
676680 . collect :: < Option < IndexVec < VariantIdx , _ > > > ( ) ?;
677681
682+ if inhabited_variants < 2 {
683+ // If there's only one inhabited variant, the no-tag layout will be equivalent to
684+ // what the niched layout would be. Returning `None` here lets us assume there is
685+ // another inhabited variant which simplifies the rest of the layout computation.
686+ return None ;
687+ }
688+
689+ // Choose the largest variant, picking an inhabited variant in a tie
678690 let largest_variant_index = variant_layouts
679691 . iter_enumerated ( )
680- . max_by_key ( |( _i, layout) | layout. size . bytes ( ) )
692+ . max_by_key ( |( _i, layout) | ( layout. size . bytes ( ) , !layout . uninhabited ) )
681693 . map ( |( i, _layout) | i) ?;
682694
695+ if variant_layouts[ largest_variant_index] . uninhabited {
696+ // If the largest variant is uninhabited, then filling its niche would give
697+ // a worse layout than the tagged layout.
698+ return None ;
699+ }
700+
683701 let all_indices = variants. indices ( ) ;
684- let needs_disc =
685- |index : VariantIdx | index != largest_variant_index && !absent ( & variants[ index] ) ;
702+ let needs_disc = |index : VariantIdx | {
703+ index != largest_variant_index && !variant_layouts[ index] . uninhabited
704+ } ;
686705 let niche_variants = all_indices. clone ( ) . find ( |v| needs_disc ( * v) ) . unwrap ( )
687706 ..=all_indices. rev ( ) . find ( |v| needs_disc ( * v) ) . unwrap ( ) ;
688707
@@ -699,6 +718,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
699718 let all_variants_fit = variant_layouts. iter_enumerated_mut ( ) . all ( |( i, layout) | {
700719 if i == largest_variant_index {
701720 return true ;
721+ } else if layout. uninhabited {
722+ // This variant doesn't need to hold space for the niche,
723+ // it just needs to be at-most-as big and aligned as the enum.
724+ return layout. size <= size && layout. align . abi <= align. abi ;
702725 }
703726
704727 layout. largest_niche = None ;
@@ -743,14 +766,14 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
743766
744767 let largest_niche = Niche :: from_scalar ( dl, niche_offset, niche_scalar) ;
745768
746- let others_zst = variant_layouts
747- . iter_enumerated ( )
748- . all ( | ( i , layout ) | i == largest_variant_index || layout . size == Size :: ZERO ) ;
769+ let others_zst_or_uninhabited = variant_layouts. iter_enumerated ( ) . all ( | ( i , layout ) | {
770+ i == largest_variant_index || layout . size == Size :: ZERO || layout . uninhabited
771+ } ) ;
749772 let same_size = size == variant_layouts[ largest_variant_index] . size ;
750773 let same_align = align == variant_layouts[ largest_variant_index] . align ;
751774
752775 let uninhabited = variant_layouts. iter ( ) . all ( |v| v. is_uninhabited ( ) ) ;
753- let abi = if same_size && same_align && others_zst {
776+ let abi = if same_size && same_align && others_zst_or_uninhabited {
754777 match variant_layouts[ largest_variant_index] . backend_repr {
755778 // When the total alignment and size match, we can use the
756779 // same ABI as the scalar variant with the reserved niche.
0 commit comments