@@ -897,7 +897,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
897897 }
898898
899899 // Create the set of structs that represent each variant.
900- let mut variants = variants. into_iter ( ) . enumerate ( ) . map ( |( i, field_layouts) | {
900+ let mut layout_variants = variants. iter ( ) . enumerate ( ) . map ( |( i, field_layouts) | {
901901 let mut st = univariant_uninterned ( & field_layouts,
902902 & def. repr , StructKind :: Prefixed ( min_ity. size ( ) , prefix_align) ) ?;
903903 st. variants = Variants :: Single { index : i } ;
@@ -958,7 +958,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
958958 // Patch up the variants' first few fields.
959959 let old_ity_size = min_ity. size ( ) ;
960960 let new_ity_size = ity. size ( ) ;
961- for variant in & mut variants {
961+ for variant in & mut layout_variants {
962962 if variant. abi == Abi :: Uninhabited {
963963 continue ;
964964 }
@@ -985,15 +985,80 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
985985 value : Int ( ity, signed) ,
986986 valid_range : ( min as u128 & tag_mask) ..=( max as u128 & tag_mask) ,
987987 } ;
988- let abi = if tag. value . size ( dl) == size {
989- Abi :: Scalar ( tag. clone ( ) )
990- } else {
991- Abi :: Aggregate { sized : true }
992- } ;
988+ let mut abi = Abi :: Aggregate { sized : true } ;
989+ if tag. value . size ( dl) == size {
990+ abi = Abi :: Scalar ( tag. clone ( ) ) ;
991+ } else if !tag. is_bool ( ) {
992+ // HACK(nox): Blindly using ScalarPair for all tagged enums
993+ // where applicable leads to Option<u8> being handled as {i1, i8},
994+ // which later confuses SROA and some loop optimisations,
995+ // ultimately leading to the repeat-trusted-len test
996+ // failing. We make the trade-off of using ScalarPair only
997+ // for types where the tag isn't a boolean.
998+ let mut common_prim = None ;
999+ for ( field_layouts, layout_variant) in variants. iter ( ) . zip ( & layout_variants) {
1000+ let offsets = match layout_variant. fields {
1001+ FieldPlacement :: Arbitrary { ref offsets, .. } => offsets,
1002+ _ => bug ! ( ) ,
1003+ } ;
1004+ let mut fields = field_layouts
1005+ . iter ( )
1006+ . zip ( offsets)
1007+ . filter ( |p| !p. 0 . is_zst ( ) ) ;
1008+ let ( field, offset) = match ( fields. next ( ) , fields. next ( ) ) {
1009+ ( None , None ) => continue ,
1010+ ( Some ( pair) , None ) => pair,
1011+ _ => {
1012+ common_prim = None ;
1013+ break ;
1014+ }
1015+ } ;
1016+ let prim = match field. details . abi {
1017+ Abi :: Scalar ( ref scalar) => scalar. value ,
1018+ _ => {
1019+ common_prim = None ;
1020+ break ;
1021+ }
1022+ } ;
1023+ if let Some ( pair) = common_prim {
1024+ // This is pretty conservative. We could go fancier
1025+ // by conflating things like i32 and u32, or even
1026+ // realising that (u8, u8) could just cohabit with
1027+ // u16 or even u32.
1028+ if pair != ( prim, offset) {
1029+ common_prim = None ;
1030+ break ;
1031+ }
1032+ } else {
1033+ common_prim = Some ( ( prim, offset) ) ;
1034+ }
1035+ }
1036+ if let Some ( ( prim, offset) ) = common_prim {
1037+ let pair = scalar_pair ( tag. clone ( ) , scalar_unit ( prim) ) ;
1038+ let pair_offsets = match pair. fields {
1039+ FieldPlacement :: Arbitrary {
1040+ ref offsets,
1041+ ref memory_index
1042+ } => {
1043+ assert_eq ! ( memory_index, & [ 0 , 1 ] ) ;
1044+ offsets
1045+ }
1046+ _ => bug ! ( )
1047+ } ;
1048+ if pair_offsets[ 0 ] == Size :: from_bytes ( 0 ) &&
1049+ pair_offsets[ 1 ] == * offset &&
1050+ align == pair. align &&
1051+ size == pair. size {
1052+ // We can use `ScalarPair` only when it matches our
1053+ // already computed layout (including `#[repr(C)]`).
1054+ abi = pair. abi ;
1055+ }
1056+ }
1057+ }
9931058 tcx. intern_layout ( LayoutDetails {
9941059 variants : Variants :: Tagged {
9951060 discr : tag,
996- variants
1061+ variants : layout_variants ,
9971062 } ,
9981063 fields : FieldPlacement :: Arbitrary {
9991064 offsets : vec ! [ Size :: from_bytes( 0 ) ] ,
0 commit comments