@@ -658,12 +658,16 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
658
658
let mut align = dl. aggregate_align ;
659
659
let mut max_repr_align = repr. align ;
660
660
let mut unadjusted_abi_align = align;
661
+ let mut inhabited_variants = 0 ;
661
662
662
663
let mut variant_layouts = variants
663
664
. iter_enumerated ( )
664
665
. map ( |( j, v) | {
665
666
let mut st = self . univariant ( v, repr, StructKind :: AlwaysSized ) . ok ( ) ?;
666
667
st. variants = Variants :: Single { index : j, variants : None } ;
668
+ if !st. uninhabited {
669
+ inhabited_variants += 1 ;
670
+ }
667
671
668
672
align = align. max ( st. align . abi ) ;
669
673
max_repr_align = max_repr_align. max ( st. max_repr_align ) ;
@@ -673,14 +677,29 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
673
677
} )
674
678
. collect :: < Option < IndexVec < VariantIdx , _ > > > ( ) ?;
675
679
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
676
688
let largest_variant_index = variant_layouts
677
689
. iter_enumerated ( )
678
- . max_by_key ( |( _i, layout) | layout. size . bytes ( ) )
690
+ . max_by_key ( |( _i, layout) | ( layout. size . bytes ( ) , !layout . uninhabited ) )
679
691
. map ( |( i, _layout) | i) ?;
680
692
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
+
681
699
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
+ } ;
684
703
let niche_variants = all_indices. clone ( ) . find ( |v| needs_disc ( * v) ) . unwrap ( )
685
704
..=all_indices. rev ( ) . find ( |v| needs_disc ( * v) ) . unwrap ( ) ;
686
705
@@ -697,6 +716,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
697
716
let all_variants_fit = variant_layouts. iter_enumerated_mut ( ) . all ( |( i, layout) | {
698
717
if i == largest_variant_index {
699
718
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;
700
723
}
701
724
702
725
layout. largest_niche = None ;
@@ -741,14 +764,14 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
741
764
742
765
let largest_niche = Niche :: from_scalar ( dl, niche_offset, niche_scalar) ;
743
766
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
+ } ) ;
747
770
let same_size = size == variant_layouts[ largest_variant_index] . size ;
748
771
let same_align = align == variant_layouts[ largest_variant_index] . align . abi ;
749
772
750
773
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 {
752
775
match variant_layouts[ largest_variant_index] . backend_repr {
753
776
// When the total alignment and size match, we can use the
754
777
// same ABI as the scalar variant with the reserved niche.
0 commit comments