@@ -729,34 +729,43 @@ pub trait LayoutCalculator {
729729 align = align. max ( AbiAndPrefAlign :: new ( repr_align) ) ;
730730 }
731731
732- let mut optimize = !repr. inhibit_union_abi_opt ( ) ;
732+ // If all the non-ZST fields have the same ABI and union ABI optimizations aren't
733+ // disabled, we can use that common ABI for the union as a whole.
734+ struct AbiMismatch ;
735+ let mut common_non_zst_abi_and_align = if repr. inhibit_union_abi_opt ( ) {
736+ // Can't optimize
737+ Err ( AbiMismatch )
738+ } else {
739+ Ok ( None )
740+ } ;
741+
733742 let mut size = Size :: ZERO ;
734- let mut common_non_zst_abi_and_align: Option < ( Abi , AbiAndPrefAlign ) > = None ;
735743 let only_variant = & variants[ FIRST_VARIANT ] ;
736744 for field in only_variant {
737745 assert ! ( field. 0 . is_sized( ) ) ;
738746
739- if !field. 0 . is_zst ( ) && optimize {
747+ if !field. 0 . is_zst ( ) && !common_non_zst_abi_and_align . is_err ( ) {
740748 // Discard valid range information and allow undef
741749 let field_abi = field. abi ( ) . to_union ( ) ;
742750
743- if let Some ( ( abi , align ) ) = & mut common_non_zst_abi_and_align {
744- if * abi != field_abi {
751+ if let Ok ( Some ( ( common_abi , common_align ) ) ) = & mut common_non_zst_abi_and_align {
752+ if * common_abi != field_abi {
745753 // Different fields have different ABI: disable opt
746- optimize = false ;
754+ common_non_zst_abi_and_align = Err ( AbiMismatch ) ;
747755 } else {
748756 // Fields with the same non-Aggregate ABI should also
749757 // have the same alignment
750- if !matches ! ( abi , Abi :: Aggregate { .. } ) {
758+ if !matches ! ( common_abi , Abi :: Aggregate { .. } ) {
751759 assert_eq ! (
752- align . abi ,
760+ * common_align ,
753761 field. align( ) . abi,
754762 "non-Aggregate field with matching ABI but differing alignment"
755763 ) ;
756764 }
757765 }
758766 } else {
759- common_non_zst_abi_and_align = Some ( ( field_abi, field. align ( ) ) ) ;
767+ // First non-ZST field: record its ABI and alignment
768+ common_non_zst_abi_and_align = Ok ( Some ( ( field_abi, field. align ( ) . abi ) ) ) ;
760769 }
761770 }
762771
@@ -770,11 +779,11 @@ pub trait LayoutCalculator {
770779
771780 // If all non-ZST fields have the same ABI, we may forward that ABI
772781 // 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, _) ) ) => {
782+ let abi = match common_non_zst_abi_and_align {
783+ Err ( AbiMismatch ) | Ok ( None ) => Abi :: Aggregate { sized : true } ,
784+ Ok ( Some ( ( abi, _) ) ) => {
776785 if abi. inherent_align ( dl) . map ( |a| a. abi ) != Some ( align. abi ) {
777- // Mismatched alignment: disable opt
786+ // Mismatched alignment (e.g. union is #[repr(packed)]) : disable opt
778787 Abi :: Aggregate { sized : true }
779788 } else {
780789 abi
0 commit comments