@@ -897,7 +897,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
897
897
}
898
898
899
899
// 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) | {
901
901
let mut st = univariant_uninterned ( & field_layouts,
902
902
& def. repr , StructKind :: Prefixed ( min_ity. size ( ) , prefix_align) ) ?;
903
903
st. variants = Variants :: Single { index : i } ;
@@ -958,7 +958,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
958
958
// Patch up the variants' first few fields.
959
959
let old_ity_size = min_ity. size ( ) ;
960
960
let new_ity_size = ity. size ( ) ;
961
- for variant in & mut variants {
961
+ for variant in & mut layout_variants {
962
962
if variant. abi == Abi :: Uninhabited {
963
963
continue ;
964
964
}
@@ -985,15 +985,80 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
985
985
value : Int ( ity, signed) ,
986
986
valid_range : ( min as u128 & tag_mask) ..=( max as u128 & tag_mask) ,
987
987
} ;
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
+ }
993
1058
tcx. intern_layout ( LayoutDetails {
994
1059
variants : Variants :: Tagged {
995
1060
discr : tag,
996
- variants
1061
+ variants : layout_variants ,
997
1062
} ,
998
1063
fields : FieldPlacement :: Arbitrary {
999
1064
offsets : vec ! [ Size :: from_bytes( 0 ) ] ,
0 commit comments