@@ -794,7 +794,7 @@ fn univariant(
794794 let mut align = if pack. is_some ( ) { dl. i8_align } else { dl. aggregate_align } ;
795795 let mut inverse_memory_index: IndexVec < u32 , FieldIdx > = fields. indices ( ) . collect ( ) ;
796796 let optimize = !repr. inhibit_struct_field_reordering_opt ( ) ;
797- if optimize {
797+ if optimize && fields . len ( ) > 1 {
798798 let end = if let StructKind :: MaybeUnsized = kind { fields. len ( ) - 1 } else { fields. len ( ) } ;
799799 let optimizing = & mut inverse_memory_index. raw [ ..end] ;
800800
@@ -814,7 +814,12 @@ fn univariant(
814814 // Otherwise we just leave things alone and actually optimize the type's fields
815815 } else {
816816 let max_field_align = fields. iter ( ) . map ( |f| f. align ( ) . abi . bytes ( ) ) . max ( ) . unwrap_or ( 1 ) ;
817- let any_niche = fields. iter ( ) . any ( |f| f. largest_niche ( ) . is_some ( ) ) ;
817+ let largest_niche_size = fields
818+ . iter ( )
819+ . filter_map ( |f| f. largest_niche ( ) )
820+ . map ( |n| n. available ( dl) )
821+ . max ( )
822+ . unwrap_or ( 0 ) ;
818823
819824 // Calculates a sort key to group fields by their alignment or possibly some size-derived
820825 // pseudo-alignment.
@@ -829,13 +834,23 @@ fn univariant(
829834 //
830835 let align = layout. align ( ) . abi . bytes ( ) ;
831836 let size = layout. size ( ) . bytes ( ) ;
837+ let niche_size = layout. largest_niche ( ) . map ( |n| n. available ( dl) ) . unwrap_or ( 0 ) ;
832838 // group [u8; 4] with align-4 or [u8; 6] with align-2 fields
833839 let size_as_align = align. max ( size) . trailing_zeros ( ) ;
834- // Given `A(u8, [u8; 16])` and `B(bool, [u8; 16])` we want to bump the array
835- // to the front in the first case (for aligned loads) but keep the bool in front
836- // in the second case for its niches.
837- let size_as_align = if any_niche {
838- max_field_align. trailing_zeros ( ) . min ( size_as_align)
840+ let size_as_align = if largest_niche_size > 0 {
841+ match niche_bias {
842+ // Given `A(u8, [u8; 16])` and `B(bool, [u8; 16])` we want to bump the array
843+ // to the front in the first case (for aligned loads) but keep the bool in front
844+ // in the second case for its niches.
845+ NicheBias :: Start => max_field_align. trailing_zeros ( ) . min ( size_as_align) ,
846+ // When moving niches towards the end of the struct then for
847+ // A((u8, u8, u8, bool), (u8, bool, u8)) we want to keep the first tuple
848+ // in the align-1 group because its bool can be moved closer to the end.
849+ NicheBias :: End if niche_size == largest_niche_size => {
850+ align. trailing_zeros ( )
851+ }
852+ NicheBias :: End => size_as_align,
853+ }
839854 } else {
840855 size_as_align
841856 } ;
0 commit comments