@@ -660,12 +660,16 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
660
660
let mut align = dl. aggregate_align ;
661
661
let mut max_repr_align = repr. align ;
662
662
let mut unadjusted_abi_align = align. abi ;
663
+ let mut inhabited_variants = 0 ;
663
664
664
665
let mut variant_layouts = variants
665
666
. iter_enumerated ( )
666
667
. map ( |( j, v) | {
667
668
let mut st = self . univariant ( v, repr, StructKind :: AlwaysSized ) . ok ( ) ?;
668
669
st. variants = Variants :: Single { index : j, variants : None } ;
670
+ if !st. uninhabited {
671
+ inhabited_variants += 1 ;
672
+ }
669
673
670
674
align = align. max ( st. align ) ;
671
675
max_repr_align = max_repr_align. max ( st. max_repr_align ) ;
@@ -675,14 +679,29 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
675
679
} )
676
680
. collect :: < Option < IndexVec < VariantIdx , _ > > > ( ) ?;
677
681
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
678
690
let largest_variant_index = variant_layouts
679
691
. iter_enumerated ( )
680
- . max_by_key ( |( _i, layout) | layout. size . bytes ( ) )
692
+ . max_by_key ( |( _i, layout) | ( layout. size . bytes ( ) , !layout . uninhabited ) )
681
693
. map ( |( i, _layout) | i) ?;
682
694
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
+
683
701
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
+ } ;
686
705
let niche_variants = all_indices. clone ( ) . find ( |v| needs_disc ( * v) ) . unwrap ( )
687
706
..=all_indices. rev ( ) . find ( |v| needs_disc ( * v) ) . unwrap ( ) ;
688
707
@@ -699,6 +718,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
699
718
let all_variants_fit = variant_layouts. iter_enumerated_mut ( ) . all ( |( i, layout) | {
700
719
if i == largest_variant_index {
701
720
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 ;
702
725
}
703
726
704
727
layout. largest_niche = None ;
@@ -743,14 +766,14 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
743
766
744
767
let largest_niche = Niche :: from_scalar ( dl, niche_offset, niche_scalar) ;
745
768
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
+ } ) ;
749
772
let same_size = size == variant_layouts[ largest_variant_index] . size ;
750
773
let same_align = align == variant_layouts[ largest_variant_index] . align ;
751
774
752
775
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 {
754
777
match variant_layouts[ largest_variant_index] . backend_repr {
755
778
// When the total alignment and size match, we can use the
756
779
// same ABI as the scalar variant with the reserved niche.
0 commit comments