@@ -608,7 +608,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
608608 let mut combined_seed = repr. field_shuffle_seed ;
609609
610610 let mut variants_info = IndexVec :: < VariantIdx , _ > :: with_capacity ( variants. len ( ) ) ;
611- let mut variant_layouts = variants
611+ let variant_layouts = variants
612612 . iter ( )
613613 . map ( |v| {
614614 let st = self . univariant ( v, repr, StructKind :: AlwaysSized ) . ok ( ) ?;
@@ -624,195 +624,27 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
624624 } )
625625 . collect :: < Option < IndexVec < VariantIdx , _ > > > ( ) ?;
626626
627- let largest_variant_index = variant_layouts
628- . iter_enumerated ( )
629- . max_by_key ( |( _i, layout) | layout. size . bytes ( ) )
630- . map ( |( i, _layout) | i) ?;
631-
632- let all_indices = variants. indices ( ) ;
633- let needs_disc =
634- |index : VariantIdx | index != largest_variant_index && !absent ( & variants[ index] ) ;
635- let niche_variants = RangeInclusive {
636- start : all_indices. clone ( ) . find ( |v| needs_disc ( * v) ) . unwrap ( ) ,
637- last : all_indices. rev ( ) . find ( |v| needs_disc ( * v) ) . unwrap ( ) ,
638- } ;
639-
640- let count =
641- ( niche_variants. last . index ( ) as u128 - niche_variants. start . index ( ) as u128 ) + 1 ;
642-
643- // Use the largest niche in the largest variant.
644- let niche = variant_layouts[ largest_variant_index] . largest_niche ?;
645- let ( niche_start, niche_scalar) = niche. reserve ( dl, count) ?;
646- let niche_offset = niche. offset ;
647- let niche_size = niche. value . size ( dl) ;
648- let size = variant_layouts[ largest_variant_index] . size . align_to ( align) ;
649-
650- let all_variants_fit = variant_layouts. iter_enumerated_mut ( ) . all ( |( i, layout) | {
651- if i == largest_variant_index {
652- return true ;
653- }
654-
655- layout. largest_niche = None ;
656-
657- if layout. size <= niche_offset {
658- // This variant will fit before the niche.
659- return true ;
660- }
661-
662- // Determine if it'll fit after the niche.
663- let this_align = variants_info[ i] . align_abi ;
664- let this_offset = ( niche_offset + niche_size) . align_to ( this_align) ;
665-
666- if this_offset + layout. size > size {
667- return false ;
668- }
669-
670- // It'll fit, but we need to make some adjustments.
671- for offset in layout. field_offsets . iter_mut ( ) {
672- * offset += this_offset;
673- }
674-
675- // It can't be a Scalar or ScalarPair because the offset isn't 0.
676- if !layout. is_uninhabited ( ) {
677- layout. backend_repr = BackendRepr :: Memory { sized : true } ;
678- }
679- layout. size += this_offset;
680-
681- true
682- } ) ;
683-
684- if !all_variants_fit {
685- return None ;
686- }
687-
688- let largest_niche = Niche :: from_scalar ( dl, niche_offset, niche_scalar) ;
689-
690- let others_zst = variant_layouts
691- . iter_enumerated ( )
692- . all ( |( i, layout) | i == largest_variant_index || layout. size == Size :: ZERO ) ;
693- let same_size = size == variant_layouts[ largest_variant_index] . size ;
694- let same_align = align == variants_info[ largest_variant_index] . align_abi ;
695-
696- let uninhabited = variant_layouts. iter ( ) . all ( |v| v. is_uninhabited ( ) ) ;
697- let abi = if same_size && same_align && others_zst {
698- match variant_layouts[ largest_variant_index] . backend_repr {
699- // When the total alignment and size match, we can use the
700- // same ABI as the scalar variant with the reserved niche.
701- BackendRepr :: Scalar ( _) => BackendRepr :: Scalar ( niche_scalar) ,
702- BackendRepr :: ScalarPair ( first, second) => {
703- // Only the niche is guaranteed to be initialised,
704- // so use union layouts for the other primitive.
705- if niche_offset == Size :: ZERO {
706- BackendRepr :: ScalarPair ( niche_scalar, second. to_union ( ) )
707- } else {
708- BackendRepr :: ScalarPair ( first. to_union ( ) , niche_scalar)
709- }
710- }
711- _ => BackendRepr :: Memory { sized : true } ,
712- }
713- } else {
714- BackendRepr :: Memory { sized : true }
715- } ;
716-
717- let layout = LayoutData {
718- variants : Variants :: Multiple {
719- tag : niche_scalar,
720- tag_encoding : TagEncoding :: Niche {
721- untagged_variant : largest_variant_index,
722- niche_variants,
723- niche_start,
724- } ,
725- tag_field : FieldIdx :: new ( 0 ) ,
726- variants : variant_layouts,
727- } ,
728- fields : FieldsShape :: Arbitrary {
729- offsets : [ niche_offset] . into ( ) ,
730- in_memory_order : [ FieldIdx :: new ( 0 ) ] . into ( ) ,
731- } ,
732- backend_repr : abi,
733- largest_niche,
734- uninhabited,
735- size,
736- align : AbiAlign :: new ( align) ,
737- max_repr_align,
738- unadjusted_abi_align,
739- randomization_seed : combined_seed,
740- } ;
741-
742- Some ( layout)
743- } ;
744-
745- let calculate_niche_filling_layout_repacked =
746- || -> Option < LayoutData < FieldIdx , VariantIdx > > {
747- struct VariantLayoutInfo {
748- align_abi : Align ,
749- }
750-
751- if repr. inhibit_enum_layout_opt ( ) {
752- return None ;
753- }
754-
755- if variants. len ( ) < 2 {
756- return None ;
757- }
758-
759- let mut align = dl. aggregate_align ;
760- let mut max_repr_align = repr. align ;
761- let mut unadjusted_abi_align = align;
762- let mut combined_seed = repr. field_shuffle_seed ;
763-
764- let mut variants_info = IndexVec :: < VariantIdx , _ > :: with_capacity ( variants. len ( ) ) ;
765- let variant_layouts = variants
766- . iter ( )
767- . map ( |v| {
768- let st = self . univariant ( v, repr, StructKind :: AlwaysSized ) . ok ( ) ?;
769-
770- variants_info. push ( VariantLayoutInfo { align_abi : st. align . abi } ) ;
771-
772- align = align. max ( st. align . abi ) ;
773- max_repr_align = max_repr_align. max ( st. max_repr_align ) ;
774- unadjusted_abi_align = unadjusted_abi_align. max ( st. unadjusted_abi_align ) ;
775- combined_seed = combined_seed. wrapping_add ( st. randomization_seed ) ;
776-
777- Some ( VariantLayout :: from_layout ( st) )
778- } )
779- . collect :: < Option < IndexVec < VariantIdx , _ > > > ( ) ?;
780-
781- let max_variant_size = variant_layouts. iter ( ) . map ( |layout| layout. size ) . max ( ) ?;
782-
783- // Chooses the first max-sized niche-providing variant whose layout succeeds.
784- for ( largest_variant_index, _) in
785- variant_layouts. iter_enumerated ( ) . filter ( |& ( _, layout) | {
786- layout. size == max_variant_size && layout. largest_niche . is_some ( )
787- } )
788- {
627+ let try_niche_variant =
628+ |largest_variant_index : VariantIdx | -> Option < LayoutData < FieldIdx , VariantIdx > > {
629+ //so niche_variant candidates don't contaminate each other if one fails
789630 let mut variant_layouts = variant_layouts. clone ( ) ;
790631
791632 let all_indices = variants. indices ( ) ;
792633 let needs_disc = |index : VariantIdx | {
793634 index != largest_variant_index && !absent ( & variants[ index] )
794635 } ;
795- let Some ( niche_variants_start) = all_indices. clone ( ) . find ( |v| needs_disc ( * v) )
796- else {
797- continue ;
798- } ;
799- let Some ( niche_variants_end) = all_indices. rev ( ) . find ( |v| needs_disc ( * v) )
800- else {
801- continue ;
636+ let niche_variants = RangeInclusive {
637+ start : all_indices. clone ( ) . find ( |v| needs_disc ( * v) ) . unwrap ( ) ,
638+ last : all_indices. rev ( ) . find ( |v| needs_disc ( * v) ) . unwrap ( ) ,
802639 } ;
803- let niche_variants = niche_variants_start..=niche_variants_end;
804640
805- let count = ( niche_variants. end ( ) . index ( ) as u128
806- - niche_variants. start ( ) . index ( ) as u128 )
641+ let count = ( niche_variants. last . index ( ) as u128
642+ - niche_variants. start . index ( ) as u128 )
807643 + 1 ;
808644
809645 // Use the largest niche in the largest variant.
810- let Some ( niche) = variant_layouts[ largest_variant_index] . largest_niche else {
811- continue ;
812- } ;
813- let Some ( ( niche_start, niche_scalar) ) = niche. reserve ( dl, count) else {
814- continue ;
815- } ;
646+ let niche = variant_layouts[ largest_variant_index] . largest_niche ?;
647+ let ( niche_start, niche_scalar) = niche. reserve ( dl, count) ?;
816648 let niche_offset = niche. offset ;
817649 let niche_size = niche. value . size ( dl) ;
818650 let size = variant_layouts[ largest_variant_index] . size . align_to ( align) ;
@@ -834,41 +666,46 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
834666 let this_align = variants_info[ i] . align_abi ;
835667 let this_offset = ( niche_offset + niche_size) . align_to ( this_align) ;
836668
837- if this_offset + layout. size > size {
838- // The ordinary niche-filling path can only move a non-largest variant as a
839- // whole before or after the chosen niche. If that fails, try placing the
840- // variant's fields individually while treating the niche bytes as reserved.
841- if let Some ( repacked) = self . try_layout_variant_around_niche (
842- & variants[ i] ,
843- repr,
844- i,
845- size,
846- align,
847- niche_offset,
848- niche_size,
849- ) {
850- * layout = VariantLayout :: from_layout ( repacked) ;
851- return true ;
669+ if this_offset + layout. size <= size {
670+ // It'll fit, but we need to make some adjustments.
671+ for offset in layout. field_offsets . iter_mut ( ) {
672+ * offset += this_offset;
852673 }
853- return false ;
854- }
855674
856- // It'll fit, but we need to make some adjustments.
857- for offset in layout. field_offsets . iter_mut ( ) {
858- * offset += this_offset;
859- }
675+ // It can't be a Scalar or ScalarPair because the offset isn't 0.
676+ if !layout. is_uninhabited ( ) {
677+ layout. backend_repr = BackendRepr :: Memory { sized : true } ;
678+ }
679+ layout. size += this_offset;
860680
861- // It can't be a Scalar or ScalarPair because the offset isn't 0.
862- if !layout. is_uninhabited ( ) {
863- layout. backend_repr = BackendRepr :: Memory { sized : true } ;
681+ return true ;
682+ }
683+ // Repacking is currently only on future edition. For editions where it is disabled,
684+ // fall back to the original niche-filling behaviour.
685+ if !repr. can_repack_variant_around_niche ( ) {
686+ return false ;
687+ }
688+ // The ordinary niche-filling path can only move a non-largest variant as a
689+ // whole before or after the chosen niche. If that fails, try placing the
690+ // variant's fields individually while treating the niche bytes as reserved.
691+ if let Some ( repacked) = self . try_layout_variant_around_niche (
692+ & variants[ i] ,
693+ repr,
694+ i,
695+ size,
696+ align,
697+ niche_offset,
698+ niche_size,
699+ ) {
700+ * layout = VariantLayout :: from_layout ( repacked) ;
701+ return true ;
864702 }
865- layout. size += this_offset;
866703
867- true
704+ false
868705 } ) ;
869706
870707 if !all_variants_fit {
871- continue ;
708+ return None ;
872709 }
873710
874711 let largest_niche = Niche :: from_scalar ( dl, niche_offset, niche_scalar) ;
@@ -900,7 +737,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
900737 BackendRepr :: Memory { sized : true }
901738 } ;
902739
903- return Some ( LayoutData {
740+ let layout = LayoutData {
904741 variants : Variants :: Multiple {
905742 tag : niche_scalar,
906743 tag_encoding : TagEncoding :: Niche {
@@ -923,18 +760,35 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
923760 max_repr_align,
924761 unadjusted_abi_align,
925762 randomization_seed : combined_seed,
926- } ) ;
763+ } ;
764+
765+ Some ( layout)
766+ } ;
767+ if repr. can_repack_variant_around_niche ( ) {
768+ let max_variant_size = variant_layouts. iter ( ) . map ( |layout| layout. size ) . max ( ) ?;
769+ // Chooses the first max-sized niche-providing variant whose layout succeeds.
770+ for ( largest_variant_index, _) in
771+ variant_layouts. iter_enumerated ( ) . filter ( |& ( _, layout) | {
772+ layout. size == max_variant_size && layout. largest_niche . is_some ( )
773+ } )
774+ {
775+ if let Some ( layout) = try_niche_variant ( largest_variant_index) {
776+ return Some ( layout) ;
777+ }
927778 }
928779
929780 None
930- } ;
931-
932- let niche_filling_layout = if repr. can_repack_variant_around_niche ( ) {
933- calculate_niche_filling_layout_repacked ( )
934- } else {
935- calculate_niche_filling_layout ( )
781+ } else {
782+ let largest_variant_index = variant_layouts
783+ . iter_enumerated ( )
784+ . max_by_key ( |( _i, layout) | layout. size . bytes ( ) )
785+ . map ( |( i, _layout) | i) ?;
786+ try_niche_variant ( largest_variant_index)
787+ }
936788 } ;
937789
790+ let niche_filling_layout = calculate_niche_filling_layout ( ) ;
791+
938792 let discr_type = repr. discr_type ( ) ;
939793 let discr_int = Integer :: from_attr ( dl, discr_type) ;
940794 // Because we can only represent one range of valid values, we'll look for the
0 commit comments