@@ -40,6 +40,8 @@ pub trait LayoutCalculator {
40
40
largest_niche,
41
41
align,
42
42
size,
43
+ max_repr_align : None ,
44
+ unadjusted_abi_align : align. abi ,
43
45
}
44
46
}
45
47
@@ -122,6 +124,8 @@ pub trait LayoutCalculator {
122
124
largest_niche : None ,
123
125
align : dl. i8_align ,
124
126
size : Size :: ZERO ,
127
+ max_repr_align : None ,
128
+ unadjusted_abi_align : dl. i8_align . abi ,
125
129
}
126
130
}
127
131
@@ -289,13 +293,18 @@ pub trait LayoutCalculator {
289
293
}
290
294
291
295
let mut align = dl. aggregate_align ;
296
+ let mut max_repr_align = repr. align ;
297
+ let mut unadjusted_abi_align = align. abi ;
298
+
292
299
let mut variant_layouts = variants
293
300
. iter_enumerated ( )
294
301
. map ( |( j, v) | {
295
302
let mut st = self . univariant ( dl, v, repr, StructKind :: AlwaysSized ) ?;
296
303
st. variants = Variants :: Single { index : j } ;
297
304
298
305
align = align. max ( st. align ) ;
306
+ max_repr_align = max_repr_align. max ( st. max_repr_align ) ;
307
+ unadjusted_abi_align = unadjusted_abi_align. max ( st. unadjusted_abi_align ) ;
299
308
300
309
Some ( st)
301
310
} )
@@ -422,6 +431,8 @@ pub trait LayoutCalculator {
422
431
largest_niche,
423
432
size,
424
433
align,
434
+ max_repr_align,
435
+ unadjusted_abi_align,
425
436
} ;
426
437
427
438
Some ( TmpLayout { layout, variants : variant_layouts } )
@@ -456,6 +467,9 @@ pub trait LayoutCalculator {
456
467
let ( min_ity, signed) = discr_range_of_repr ( min, max) ; //Integer::repr_discr(tcx, ty, &repr, min, max);
457
468
458
469
let mut align = dl. aggregate_align ;
470
+ let mut max_repr_align = repr. align ;
471
+ let mut unadjusted_abi_align = align. abi ;
472
+
459
473
let mut size = Size :: ZERO ;
460
474
461
475
// We're interested in the smallest alignment, so start large.
@@ -498,6 +512,8 @@ pub trait LayoutCalculator {
498
512
}
499
513
size = cmp:: max ( size, st. size ) ;
500
514
align = align. max ( st. align ) ;
515
+ max_repr_align = max_repr_align. max ( st. max_repr_align ) ;
516
+ unadjusted_abi_align = unadjusted_abi_align. max ( st. unadjusted_abi_align ) ;
501
517
Some ( st)
502
518
} )
503
519
. collect :: < Option < IndexVec < VariantIdx , _ > > > ( ) ?;
@@ -691,6 +707,8 @@ pub trait LayoutCalculator {
691
707
abi,
692
708
align,
693
709
size,
710
+ max_repr_align,
711
+ unadjusted_abi_align,
694
712
} ;
695
713
696
714
let tagged_layout = TmpLayout { layout : tagged_layout, variants : layout_variants } ;
@@ -730,10 +748,7 @@ pub trait LayoutCalculator {
730
748
let dl = self . current_data_layout ( ) ;
731
749
let dl = dl. borrow ( ) ;
732
750
let mut align = if repr. pack . is_some ( ) { dl. i8_align } else { dl. aggregate_align } ;
733
-
734
- if let Some ( repr_align) = repr. align {
735
- align = align. max ( AbiAndPrefAlign :: new ( repr_align) ) ;
736
- }
751
+ let mut max_repr_align = repr. align ;
737
752
738
753
// If all the non-ZST fields have the same ABI and union ABI optimizations aren't
739
754
// disabled, we can use that common ABI for the union as a whole.
@@ -751,6 +766,7 @@ pub trait LayoutCalculator {
751
766
assert ! ( field. 0 . is_sized( ) ) ;
752
767
753
768
align = align. max ( field. align ( ) ) ;
769
+ max_repr_align = max_repr_align. max ( field. max_repr_align ( ) ) ;
754
770
size = cmp:: max ( size, field. size ( ) ) ;
755
771
756
772
if field. 0 . is_zst ( ) {
@@ -787,6 +803,14 @@ pub trait LayoutCalculator {
787
803
if let Some ( pack) = repr. pack {
788
804
align = align. min ( AbiAndPrefAlign :: new ( pack) ) ;
789
805
}
806
+ // The unadjusted ABI alignment does not include repr(align), but does include repr(pack).
807
+ // See documentation on `LayoutS::unadjusted_abi_align`.
808
+ let unadjusted_abi_align = align. abi ;
809
+ if let Some ( repr_align) = repr. align {
810
+ align = align. max ( AbiAndPrefAlign :: new ( repr_align) ) ;
811
+ }
812
+ // `align` must not be modified after this, or `unadjusted_abi_align` could be inaccurate.
813
+ let align = align;
790
814
791
815
// If all non-ZST fields have the same ABI, we may forward that ABI
792
816
// for the union as a whole, unless otherwise inhibited.
@@ -809,6 +833,8 @@ pub trait LayoutCalculator {
809
833
largest_niche : None ,
810
834
align,
811
835
size : size. align_to ( align. abi ) ,
836
+ max_repr_align,
837
+ unadjusted_abi_align,
812
838
} )
813
839
}
814
840
}
@@ -829,6 +855,7 @@ fn univariant(
829
855
) -> Option < LayoutS > {
830
856
let pack = repr. pack ;
831
857
let mut align = if pack. is_some ( ) { dl. i8_align } else { dl. aggregate_align } ;
858
+ let mut max_repr_align = repr. align ;
832
859
let mut inverse_memory_index: IndexVec < u32 , FieldIdx > = fields. indices ( ) . collect ( ) ;
833
860
let optimize = !repr. inhibit_struct_field_reordering_opt ( ) ;
834
861
if optimize && fields. len ( ) > 1 {
@@ -997,6 +1024,7 @@ fn univariant(
997
1024
} ;
998
1025
offset = offset. align_to ( field_align. abi ) ;
999
1026
align = align. max ( field_align) ;
1027
+ max_repr_align = max_repr_align. max ( field. max_repr_align ( ) ) ;
1000
1028
1001
1029
debug ! ( "univariant offset: {:?} field: {:#?}" , offset, field) ;
1002
1030
offsets[ i] = offset;
@@ -1018,9 +1046,16 @@ fn univariant(
1018
1046
1019
1047
offset = offset. checked_add ( field. size ( ) , dl) ?;
1020
1048
}
1049
+
1050
+ // The unadjusted ABI alignment does not include repr(align), but does include repr(pack).
1051
+ // See documentation on `LayoutS::unadjusted_abi_align`.
1052
+ let unadjusted_abi_align = align. abi ;
1021
1053
if let Some ( repr_align) = repr. align {
1022
1054
align = align. max ( AbiAndPrefAlign :: new ( repr_align) ) ;
1023
1055
}
1056
+ // `align` must not be modified after this point, or `unadjusted_abi_align` could be inaccurate.
1057
+ let align = align;
1058
+
1024
1059
debug ! ( "univariant min_size: {:?}" , offset) ;
1025
1060
let min_size = offset;
1026
1061
// As stated above, inverse_memory_index holds field indices by increasing offset.
@@ -1036,6 +1071,7 @@ fn univariant(
1036
1071
inverse_memory_index. into_iter ( ) . map ( FieldIdx :: as_u32) . collect ( )
1037
1072
} ;
1038
1073
let size = min_size. align_to ( align. abi ) ;
1074
+ let mut layout_of_single_non_zst_field = None ;
1039
1075
let mut abi = Abi :: Aggregate { sized } ;
1040
1076
// Unpack newtype ABIs and find scalar pairs.
1041
1077
if sized && size. bytes ( ) > 0 {
@@ -1045,6 +1081,8 @@ fn univariant(
1045
1081
match ( non_zst_fields. next ( ) , non_zst_fields. next ( ) , non_zst_fields. next ( ) ) {
1046
1082
// We have exactly one non-ZST field.
1047
1083
( Some ( ( i, field) ) , None , None ) => {
1084
+ layout_of_single_non_zst_field = Some ( field) ;
1085
+
1048
1086
// Field fills the struct and it has a scalar or scalar pair ABI.
1049
1087
if offsets[ i] . bytes ( ) == 0 && align. abi == field. align ( ) . abi && size == field. size ( )
1050
1088
{
@@ -1102,13 +1140,28 @@ fn univariant(
1102
1140
if fields. iter ( ) . any ( |f| f. abi ( ) . is_uninhabited ( ) ) {
1103
1141
abi = Abi :: Uninhabited ;
1104
1142
}
1143
+
1144
+ let unadjusted_abi_align = if repr. transparent ( ) {
1145
+ match layout_of_single_non_zst_field {
1146
+ Some ( l) => l. unadjusted_abi_align ( ) ,
1147
+ None => {
1148
+ // `repr(transparent)` with all ZST fields.
1149
+ align. abi
1150
+ }
1151
+ }
1152
+ } else {
1153
+ unadjusted_abi_align
1154
+ } ;
1155
+
1105
1156
Some ( LayoutS {
1106
1157
variants : Variants :: Single { index : FIRST_VARIANT } ,
1107
1158
fields : FieldsShape :: Arbitrary { offsets, memory_index } ,
1108
1159
abi,
1109
1160
largest_niche,
1110
1161
align,
1111
1162
size,
1163
+ max_repr_align,
1164
+ unadjusted_abi_align,
1112
1165
} )
1113
1166
}
1114
1167
0 commit comments