@@ -157,8 +157,10 @@ pub trait LayoutCalculator {
157157 // for non-ZST uninhabited data (mostly partial initialization).
158158 let absent = |fields : & IndexSlice < FieldIdx , Layout < ' _ > > | {
159159 let uninhabited = fields. iter ( ) . any ( |f| f. abi ( ) . is_uninhabited ( ) ) ;
160- let is_zst = fields. iter ( ) . all ( |f| f. 0 . is_zst ( ) ) ;
161- uninhabited && is_zst
160+ // We cannot ignore alignment; that might lead us to entirely discard a variant and
161+ // produce an enum that is less aligned than it should be!
162+ let is_1zst = fields. iter ( ) . all ( |f| f. 0 . is_1zst ( ) ) ;
163+ uninhabited && is_1zst
162164 } ;
163165 let ( present_first, present_second) = {
164166 let mut present_variants = variants
@@ -358,8 +360,11 @@ pub trait LayoutCalculator {
358360 match layout. fields {
359361 FieldsShape :: Arbitrary { ref mut offsets, .. } => {
360362 for ( j, offset) in offsets. iter_enumerated_mut ( ) {
363+ // keep ZST at offset 0 to simplify Scalar/ScalarPair layout
361364 if !variants[ i] [ j] . 0 . is_zst ( ) {
362365 * offset += this_offset;
366+ } else {
367+ debug_assert_eq ! ( offset. bytes( ) , 0 ) ;
363368 }
364369 }
365370 }
@@ -504,7 +509,7 @@ pub trait LayoutCalculator {
504509 // to make room for a larger discriminant.
505510 for field_idx in st. fields . index_by_increasing_offset ( ) {
506511 let field = & field_layouts[ FieldIdx :: from_usize ( field_idx) ] ;
507- if !field. 0 . is_zst ( ) || field . align ( ) . abi . bytes ( ) != 1 {
512+ if !field. 0 . is_1zst ( ) {
508513 start_align = start_align. min ( field. align ( ) . abi ) ;
509514 break ;
510515 }
@@ -603,12 +608,15 @@ pub trait LayoutCalculator {
603608 abi = Abi :: Scalar ( tag) ;
604609 } else {
605610 // Try to use a ScalarPair for all tagged enums.
611+ // That's possible only if we can find a common primitive type for all variants.
606612 let mut common_prim = None ;
607613 let mut common_prim_initialized_in_all_variants = true ;
608614 for ( field_layouts, layout_variant) in iter:: zip ( variants, & layout_variants) {
609615 let FieldsShape :: Arbitrary { ref offsets, .. } = layout_variant. fields else {
610616 panic ! ( ) ;
611617 } ;
618+ // We skip *all* ZST here and later check if we are good in terms of alignment.
619+ // This lets us handle some cases involving aligned ZST.
612620 let mut fields = iter:: zip ( field_layouts, offsets) . filter ( |p| !p. 0 . 0 . is_zst ( ) ) ;
613621 let ( field, offset) = match ( fields. next ( ) , fields. next ( ) ) {
614622 ( None , None ) => {
@@ -954,8 +962,10 @@ fn univariant(
954962 } ;
955963
956964 (
957- // Place ZSTs first to avoid "interesting offsets", especially with only one
958- // or two non-ZST fields. This helps Scalar/ScalarPair layouts.
965+ // Place ZSTs first to avoid "interesting offsets", especially with only
966+ // one or two non-ZST fields. This helps Scalar/ScalarPair layouts. Note
967+ // that these can ignore even some aligned ZST as long as the alignment
968+ // is less than that of the scalar, hence we treat *all* ZST like that.
959969 !f. 0 . is_zst ( ) ,
960970 // Then place largest alignments first.
961971 cmp:: Reverse ( alignment_group_key ( f) ) ,
@@ -1073,9 +1083,10 @@ fn univariant(
10731083 let size = min_size. align_to ( align. abi ) ;
10741084 let mut layout_of_single_non_zst_field = None ;
10751085 let mut abi = Abi :: Aggregate { sized } ;
1076- // Unpack newtype ABIs and find scalar pairs .
1086+ // Try to make this a Scalar/ScalarPair .
10771087 if sized && size. bytes ( ) > 0 {
1078- // All other fields must be ZSTs.
1088+ // We skip *all* ZST here and later check if we are good in terms of alignment.
1089+ // This lets us handle some cases involving aligned ZST.
10791090 let mut non_zst_fields = fields. iter_enumerated ( ) . filter ( |& ( _, f) | !f. 0 . is_zst ( ) ) ;
10801091
10811092 match ( non_zst_fields. next ( ) , non_zst_fields. next ( ) , non_zst_fields. next ( ) ) {
0 commit comments