@@ -729,34 +729,43 @@ pub trait LayoutCalculator {
729
729
align = align. max ( AbiAndPrefAlign :: new ( repr_align) ) ;
730
730
}
731
731
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
+
733
742
let mut size = Size :: ZERO ;
734
- let mut common_non_zst_abi_and_align: Option < ( Abi , AbiAndPrefAlign ) > = None ;
735
743
let only_variant = & variants[ FIRST_VARIANT ] ;
736
744
for field in only_variant {
737
745
assert ! ( field. 0 . is_sized( ) ) ;
738
746
739
- if !field. 0 . is_zst ( ) && optimize {
747
+ if !field. 0 . is_zst ( ) && !common_non_zst_abi_and_align . is_err ( ) {
740
748
// Discard valid range information and allow undef
741
749
let field_abi = field. abi ( ) . to_union ( ) ;
742
750
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 {
745
753
// Different fields have different ABI: disable opt
746
- optimize = false ;
754
+ common_non_zst_abi_and_align = Err ( AbiMismatch ) ;
747
755
} else {
748
756
// Fields with the same non-Aggregate ABI should also
749
757
// have the same alignment
750
- if !matches ! ( abi , Abi :: Aggregate { .. } ) {
758
+ if !matches ! ( common_abi , Abi :: Aggregate { .. } ) {
751
759
assert_eq ! (
752
- align . abi ,
760
+ * common_align ,
753
761
field. align( ) . abi,
754
762
"non-Aggregate field with matching ABI but differing alignment"
755
763
) ;
756
764
}
757
765
}
758
766
} 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 ) ) ) ;
760
769
}
761
770
}
762
771
@@ -770,11 +779,11 @@ pub trait LayoutCalculator {
770
779
771
780
// If all non-ZST fields have the same ABI, we may forward that ABI
772
781
// 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, _) ) ) => {
776
785
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
778
787
Abi :: Aggregate { sized : true }
779
788
} else {
780
789
abi
0 commit comments