@@ -729,64 +729,59 @@ pub trait LayoutCalculator {
729729 align = align. max ( AbiAndPrefAlign :: new ( repr_align) ) ;
730730 }
731731
732- let optimize = !repr. inhibit_union_abi_opt ( ) ;
732+ let mut optimize = !repr. inhibit_union_abi_opt ( ) ;
733733 let mut size = Size :: ZERO ;
734- let mut abi = None ;
735- let mut biggest_zst_align = align;
736- let mut biggest_non_zst_align = align;
734+ let mut common_non_zst_abi_and_align: Option < ( Abi , AbiAndPrefAlign ) > = None ;
737735 let only_variant = & variants[ FIRST_VARIANT ] ;
738736 for field in only_variant {
739- assert ! ( ! field. 0 . is_unsized ( ) ) ;
737+ assert ! ( field. 0 . is_sized ( ) ) ;
740738
741- if optimize {
742- // If all non-ZST fields have the same ABI, forward this ABI
743- if field. 0 . is_zst ( ) {
744- biggest_zst_align = biggest_zst_align. max ( field. align ( ) ) ;
745- } else {
746- biggest_non_zst_align = biggest_non_zst_align. max ( field. align ( ) ) ;
747- // Discard valid range information and allow undef
748- let field_abi = match field. abi ( ) {
749- Abi :: Scalar ( x) => Abi :: Scalar ( x. to_union ( ) ) ,
750- Abi :: ScalarPair ( x, y) => Abi :: ScalarPair ( x. to_union ( ) , y. to_union ( ) ) ,
751- Abi :: Vector { element : x, count } => {
752- Abi :: Vector { element : x. to_union ( ) , count }
753- }
754- Abi :: Uninhabited | Abi :: Aggregate { .. } => Abi :: Aggregate { sized : true } ,
755- } ;
739+ if !field. 0 . is_zst ( ) && optimize {
740+ // Discard valid range information and allow undef
741+ let field_abi = field. abi ( ) . to_union ( ) ;
756742
757- if let Some ( abi) = & mut abi {
758- if * abi != field_abi {
759- // different fields have different ABI: reset to Aggregate
760- * abi = Abi :: Aggregate { sized : true } ;
761- }
743+ if let Some ( ( abi, align) ) = & mut common_non_zst_abi_and_align {
744+ if * abi != field_abi {
745+ // Different fields have different ABI: disable opt
746+ optimize = false ;
762747 } else {
763- abi = Some ( field_abi) ;
748+ // Fields with the same non-Aggregate ABI should also
749+ // have the same alignment
750+ if !matches ! ( abi, Abi :: Aggregate { .. } ) {
751+ assert_eq ! (
752+ align. abi,
753+ field. align( ) . abi,
754+ "non-Aggregate field with matching ABI but differing alignment"
755+ ) ;
756+ }
764757 }
758+ } else {
759+ common_non_zst_abi_and_align = Some ( ( field_abi, field. align ( ) ) ) ;
765760 }
766761 }
767762
768763 align = align. max ( field. align ( ) ) ;
769764 size = cmp:: max ( size, field. size ( ) ) ;
770765 }
771766
772- let abi = match abi {
773- None => Abi :: Aggregate { sized : true } ,
774- Some ( non_zst_abi) => {
775- if biggest_zst_align. abi > biggest_non_zst_align. abi {
776- // If a zst has a bigger alignment than the non-zst fields,
777- // we cannot use scalar layout, because scalar(pair)s can't be
778- // more aligned than their primitive.
767+ if let Some ( pack) = repr. pack {
768+ align = align. min ( AbiAndPrefAlign :: new ( pack) ) ;
769+ }
770+
771+ // If all non-ZST fields have the same ABI, we may forward that ABI
772+ // for the union as a whole, unless otherwise inhibited.
773+ let abi = match ( optimize, common_non_zst_abi_and_align) {
774+ ( false , _) | ( _, None ) => Abi :: Aggregate { sized : true } ,
775+ ( true , Some ( ( abi, _) ) ) => {
776+ if abi. inherent_align ( dl) . map ( |a| a. abi ) != Some ( align. abi ) {
777+ // Mismatched alignment: disable opt
779778 Abi :: Aggregate { sized : true }
780779 } else {
781- non_zst_abi
780+ abi
782781 }
783782 }
784783 } ;
785784
786- if let Some ( pack) = repr. pack {
787- align = align. min ( AbiAndPrefAlign :: new ( pack) ) ;
788- }
789-
790785 Some ( LayoutS {
791786 variants : Variants :: Single { index : FIRST_VARIANT } ,
792787 fields : FieldsShape :: Union ( NonZeroUsize :: new ( only_variant. len ( ) ) ?) ,
0 commit comments