@@ -41,6 +41,7 @@ pub trait LayoutCalculator {
4141 align,
4242 size,
4343 repr_align : None ,
44+ unadjusted_abi_align : align. abi ,
4445 }
4546 }
4647
@@ -124,6 +125,7 @@ pub trait LayoutCalculator {
124125 align : dl. i8_align ,
125126 size : Size :: ZERO ,
126127 repr_align : None ,
128+ unadjusted_abi_align : dl. i8_align . abi ,
127129 }
128130 }
129131
@@ -291,13 +293,16 @@ pub trait LayoutCalculator {
291293 }
292294
293295 let mut align = dl. aggregate_align ;
296+ let mut unadjusted_abi_align = align. abi ;
297+
294298 let mut variant_layouts = variants
295299 . iter_enumerated ( )
296300 . map ( |( j, v) | {
297301 let mut st = self . univariant ( dl, v, repr, StructKind :: AlwaysSized ) ?;
298302 st. variants = Variants :: Single { index : j } ;
299303
300304 align = align. max ( st. align ) ;
305+ unadjusted_abi_align = unadjusted_abi_align. max ( st. unadjusted_abi_align ) ;
301306
302307 Some ( st)
303308 } )
@@ -425,6 +430,7 @@ pub trait LayoutCalculator {
425430 size,
426431 align,
427432 repr_align : repr. align ,
433+ unadjusted_abi_align,
428434 } ;
429435
430436 Some ( TmpLayout { layout, variants : variant_layouts } )
@@ -459,6 +465,8 @@ pub trait LayoutCalculator {
459465 let ( min_ity, signed) = discr_range_of_repr ( min, max) ; //Integer::repr_discr(tcx, ty, &repr, min, max);
460466
461467 let mut align = dl. aggregate_align ;
468+ let mut unadjusted_abi_align = align. abi ;
469+
462470 let mut size = Size :: ZERO ;
463471
464472 // We're interested in the smallest alignment, so start large.
@@ -501,6 +509,7 @@ pub trait LayoutCalculator {
501509 }
502510 size = cmp:: max ( size, st. size ) ;
503511 align = align. max ( st. align ) ;
512+ unadjusted_abi_align = unadjusted_abi_align. max ( st. unadjusted_abi_align ) ;
504513 Some ( st)
505514 } )
506515 . collect :: < Option < IndexVec < VariantIdx , _ > > > ( ) ?;
@@ -695,6 +704,7 @@ pub trait LayoutCalculator {
695704 align,
696705 size,
697706 repr_align : repr. align ,
707+ unadjusted_abi_align,
698708 } ;
699709
700710 let tagged_layout = TmpLayout { layout : tagged_layout, variants : layout_variants } ;
@@ -735,10 +745,6 @@ pub trait LayoutCalculator {
735745 let dl = dl. borrow ( ) ;
736746 let mut align = if repr. pack . is_some ( ) { dl. i8_align } else { dl. aggregate_align } ;
737747
738- if let Some ( repr_align) = repr. align {
739- align = align. max ( AbiAndPrefAlign :: new ( repr_align) ) ;
740- }
741-
742748 // If all the non-ZST fields have the same ABI and union ABI optimizations aren't
743749 // disabled, we can use that common ABI for the union as a whole.
744750 struct AbiMismatch ;
@@ -791,6 +797,14 @@ pub trait LayoutCalculator {
791797 if let Some ( pack) = repr. pack {
792798 align = align. min ( AbiAndPrefAlign :: new ( pack) ) ;
793799 }
800+ // The unadjusted ABI alignment does not include repr(align), but does include repr(pack).
801+ // See documentation on `LayoutS::unadjusted_abi_align`.
802+ let unadjusted_abi_align = align. abi ;
803+ if let Some ( repr_align) = repr. align {
804+ align = align. max ( AbiAndPrefAlign :: new ( repr_align) ) ;
805+ }
806+ // `align` must not be modified after this, or `unadjusted_abi_align` could be inaccurate.
807+ let align = align;
794808
795809 // If all non-ZST fields have the same ABI, we may forward that ABI
796810 // for the union as a whole, unless otherwise inhibited.
@@ -814,6 +828,7 @@ pub trait LayoutCalculator {
814828 align,
815829 size : size. align_to ( align. abi ) ,
816830 repr_align : repr. align ,
831+ unadjusted_abi_align,
817832 } )
818833 }
819834}
@@ -1023,9 +1038,16 @@ fn univariant(
10231038
10241039 offset = offset. checked_add ( field. size ( ) , dl) ?;
10251040 }
1041+
1042+ // The unadjusted ABI alignment does not include repr(align), but does include repr(pack).
1043+ // See documentation on `LayoutS::unadjusted_abi_align`.
1044+ let unadjusted_abi_align = align. abi ;
10261045 if let Some ( repr_align) = repr. align {
10271046 align = align. max ( AbiAndPrefAlign :: new ( repr_align) ) ;
10281047 }
1048+ // `align` must not be modified after this point, or `unadjusted_abi_align` could be inaccurate.
1049+ let align = align;
1050+
10291051 debug ! ( "univariant min_size: {:?}" , offset) ;
10301052 let min_size = offset;
10311053 // As stated above, inverse_memory_index holds field indices by increasing offset.
@@ -1111,9 +1133,29 @@ fn univariant(
11111133 abi = Abi :: Uninhabited ;
11121134 }
11131135
1114- let repr_align = repr. align . or_else ( || {
1115- if repr. transparent ( ) { layout_of_single_non_zst_field?. repr_align ( ) } else { None }
1116- } ) ;
1136+ let ( repr_align, unadjusted_abi_align) = if repr. transparent ( ) {
1137+ match layout_of_single_non_zst_field {
1138+ Some ( l) => ( l. repr_align ( ) , l. unadjusted_abi_align ( ) ) ,
1139+ None => {
1140+ // `repr(transparent)` with all ZST fields.
1141+ //
1142+ // Using `None` for `repr_align` here is technically incorrect, since one of
1143+ // the ZSTs could have `repr(align(1))`. It's an interesting question, if you have
1144+ // `#{repr(transparent)] struct Foo((), ZstWithReprAlign1)`, which of those ZSTs'
1145+ // ABIs is forwarded by `repr(transparent)`? The answer to that question determines
1146+ // whether we should use `None` or `Some(align 1)` here. Thanksfully, two things
1147+ // together mean this doesn't matter:
1148+ // - You're not allowed to have a `repr(transparent)` struct that contains
1149+ // `repr(align)` > 1 ZSTs. See error E0691.
1150+ // - MSVC never treats requested align 1 differently from natural align 1.
1151+ // (And the `repr_align` field is only used on i686-windows, see `LayoutS` docs.)
1152+ // So just use `None` for now.
1153+ ( None , align. abi )
1154+ }
1155+ }
1156+ } else {
1157+ ( repr. align , unadjusted_abi_align)
1158+ } ;
11171159
11181160 Some ( LayoutS {
11191161 variants : Variants :: Single { index : FIRST_VARIANT } ,
@@ -1123,6 +1165,7 @@ fn univariant(
11231165 align,
11241166 size,
11251167 repr_align,
1168+ unadjusted_abi_align,
11261169 } )
11271170}
11281171
0 commit comments