@@ -246,13 +246,22 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
246
246
let align = a. value . align ( dl) . max ( b_align) . max ( dl. aggregate_align ) ;
247
247
let b_offset = a. value . size ( dl) . align_to ( b_align. abi ) ;
248
248
let size = ( b_offset + b. value . size ( dl) ) . align_to ( align. abi ) ;
249
+
250
+ // HACK(nox): We iter on `b` and then `a` because `max_by_key`
251
+ // returns the last maximum.
252
+ let largest_niche = Niche :: from_scalar ( dl, b_offset, b. clone ( ) )
253
+ . into_iter ( )
254
+ . chain ( Niche :: from_scalar ( dl, Size :: ZERO , a. clone ( ) ) )
255
+ . max_by_key ( |niche| niche. available ( dl) ) ;
256
+
249
257
LayoutDetails {
250
258
variants : Variants :: Single { index : VariantIdx :: new ( 0 ) } ,
251
259
fields : FieldPlacement :: Arbitrary {
252
260
offsets : vec ! [ Size :: ZERO , b_offset] ,
253
261
memory_index : vec ! [ 0 , 1 ]
254
262
} ,
255
263
abi : Abi :: ScalarPair ( a, b) ,
264
+ largest_niche,
256
265
align,
257
266
size
258
267
}
@@ -321,6 +330,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
321
330
322
331
323
332
let mut offset = Size :: ZERO ;
333
+ let mut largest_niche = None ;
334
+ let mut largest_niche_available = 0 ;
324
335
325
336
if let StructKind :: Prefixed ( prefix_size, prefix_align) = kind {
326
337
let prefix_align = if packed {
@@ -355,6 +366,15 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
355
366
debug ! ( "univariant offset: {:?} field: {:#?}" , offset, field) ;
356
367
offsets[ i as usize ] = offset;
357
368
369
+ if let Some ( mut niche) = field. largest_niche . clone ( ) {
370
+ let available = niche. available ( dl) ;
371
+ if available > largest_niche_available {
372
+ largest_niche_available = available;
373
+ niche. offset += offset;
374
+ largest_niche = Some ( niche) ;
375
+ }
376
+ }
377
+
358
378
offset = offset. checked_add ( field. size , dl)
359
379
. ok_or ( LayoutError :: SizeOverflow ( ty) ) ?;
360
380
}
@@ -466,6 +486,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
466
486
memory_index
467
487
} ,
468
488
abi,
489
+ largest_niche,
469
490
align,
470
491
size
471
492
} )
@@ -525,6 +546,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
525
546
variants : Variants :: Single { index : VariantIdx :: new ( 0 ) } ,
526
547
fields : FieldPlacement :: Union ( 0 ) ,
527
548
abi : Abi :: Uninhabited ,
549
+ largest_niche : None ,
528
550
align : dl. i8_align ,
529
551
size : Size :: ZERO
530
552
} )
@@ -583,13 +605,20 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
583
605
Abi :: Aggregate { sized : true }
584
606
} ;
585
607
608
+ let largest_niche = if count != 0 {
609
+ element. largest_niche . clone ( )
610
+ } else {
611
+ None
612
+ } ;
613
+
586
614
tcx. intern_layout ( LayoutDetails {
587
615
variants : Variants :: Single { index : VariantIdx :: new ( 0 ) } ,
588
616
fields : FieldPlacement :: Array {
589
617
stride : element. size ,
590
618
count
591
619
} ,
592
620
abi,
621
+ largest_niche,
593
622
align : element. align ,
594
623
size
595
624
} )
@@ -603,6 +632,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
603
632
count : 0
604
633
} ,
605
634
abi : Abi :: Aggregate { sized : false } ,
635
+ largest_niche : None ,
606
636
align : element. align ,
607
637
size : Size :: ZERO
608
638
} )
@@ -615,6 +645,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
615
645
count : 0
616
646
} ,
617
647
abi : Abi :: Aggregate { sized : false } ,
648
+ largest_niche : None ,
618
649
align : dl. i8_align ,
619
650
size : Size :: ZERO
620
651
} )
@@ -683,6 +714,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
683
714
element : scalar,
684
715
count
685
716
} ,
717
+ largest_niche : element. largest_niche . clone ( ) ,
686
718
size,
687
719
align,
688
720
} )
@@ -768,6 +800,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
768
800
variants : Variants :: Single { index } ,
769
801
fields : FieldPlacement :: Union ( variants[ index] . len ( ) ) ,
770
802
abi,
803
+ largest_niche : None ,
771
804
align,
772
805
size : size. align_to ( align. abi )
773
806
} ) ) ;
@@ -829,14 +862,38 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
829
862
// `#[rustc_layout_scalar_valid_range(n)]`
830
863
// attribute to widen the range of anything as that would probably
831
864
// result in UB somewhere
865
+ // FIXME(eddyb) the asserts are probably not needed,
866
+ // as larger validity ranges would result in missed
867
+ // optimizations, *not* wrongly assuming the inner
868
+ // value is valid. e.g. unions enlarge validity ranges,
869
+ // because the values may be uninitialized.
832
870
if let Bound :: Included ( start) = start {
871
+ // FIXME(eddyb) this might be incorrect - it doesn't
872
+ // account for wrap-around (end < start) ranges.
833
873
assert ! ( * scalar. valid_range. start( ) <= start) ;
834
874
scalar. valid_range = start..=* scalar. valid_range . end ( ) ;
835
875
}
836
876
if let Bound :: Included ( end) = end {
877
+ // FIXME(eddyb) this might be incorrect - it doesn't
878
+ // account for wrap-around (end < start) ranges.
837
879
assert ! ( * scalar. valid_range. end( ) >= end) ;
838
880
scalar. valid_range = * scalar. valid_range . start ( ) ..=end;
839
881
}
882
+
883
+ // Update `largest_niche` if we have introduced a larger niche.
884
+ let niche = Niche :: from_scalar ( dl, Size :: ZERO , scalar. clone ( ) ) ;
885
+ if let Some ( niche) = niche {
886
+ match & st. largest_niche {
887
+ Some ( largest_niche) => {
888
+ // Replace the existing niche even if they're equal,
889
+ // because this one is at a lower offset.
890
+ if largest_niche. available ( dl) <= niche. available ( dl) {
891
+ st. largest_niche = Some ( niche) ;
892
+ }
893
+ }
894
+ None => st. largest_niche = Some ( niche) ,
895
+ }
896
+ }
840
897
}
841
898
_ => assert ! (
842
899
start == Bound :: Unbounded && end == Bound :: Unbounded ,
@@ -845,6 +902,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
845
902
st,
846
903
) ,
847
904
}
905
+
848
906
return Ok ( tcx. intern_layout ( st) ) ;
849
907
}
850
908
@@ -886,8 +944,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
886
944
let count = (
887
945
niche_variants. end ( ) . as_u32 ( ) - niche_variants. start ( ) . as_u32 ( ) + 1
888
946
) as u128 ;
947
+ // FIXME(#62691) use the largest niche across all fields,
948
+ // not just the first one.
889
949
for ( field_index, & field) in variants[ i] . iter ( ) . enumerate ( ) {
890
- let niche = match self . find_niche ( field) ? {
950
+ let niche = match & field. largest_niche {
891
951
Some ( niche) => niche,
892
952
_ => continue ,
893
953
} ;
@@ -937,6 +997,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
937
997
abi = Abi :: Uninhabited ;
938
998
}
939
999
1000
+
1001
+ let largest_niche =
1002
+ Niche :: from_scalar ( dl, offset, niche_scalar. clone ( ) ) ;
1003
+
940
1004
return Ok ( tcx. intern_layout ( LayoutDetails {
941
1005
variants : Variants :: Multiple {
942
1006
discr : niche_scalar,
@@ -953,6 +1017,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
953
1017
memory_index : vec ! [ 0 ]
954
1018
} ,
955
1019
abi,
1020
+ largest_niche,
956
1021
size,
957
1022
align,
958
1023
} ) ) ;
@@ -1164,6 +1229,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
1164
1229
abi = Abi :: Uninhabited ;
1165
1230
}
1166
1231
1232
+ let largest_niche = Niche :: from_scalar ( dl, Size :: ZERO , tag. clone ( ) ) ;
1233
+
1167
1234
tcx. intern_layout ( LayoutDetails {
1168
1235
variants : Variants :: Multiple {
1169
1236
discr : tag,
@@ -1175,6 +1242,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
1175
1242
offsets : vec ! [ Size :: ZERO ] ,
1176
1243
memory_index : vec ! [ 0 ]
1177
1244
} ,
1245
+ largest_niche,
1178
1246
abi,
1179
1247
align,
1180
1248
size
@@ -1332,16 +1400,31 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
1332
1400
// locals as part of the prefix. We compute the layout of all of
1333
1401
// these fields at once to get optimal packing.
1334
1402
let discr_index = substs. prefix_tys ( def_id, tcx) . count ( ) ;
1335
- let promoted_tys =
1336
- ineligible_locals. iter ( ) . map ( |local| subst_field ( info. field_tys [ local] ) ) ;
1337
- let prefix_tys = substs. prefix_tys ( def_id, tcx)
1338
- . chain ( iter:: once ( substs. discr_ty ( tcx) ) )
1339
- . chain ( promoted_tys) ;
1340
- let prefix = self . univariant_uninterned (
1403
+ // FIXME(eddyb) set the correct vaidity range for the discriminant.
1404
+ let discr_layout = self . layout_of ( substs. discr_ty ( tcx) ) ?;
1405
+ let discr = match & discr_layout. abi {
1406
+ Abi :: Scalar ( s) => s. clone ( ) ,
1407
+ _ => bug ! ( ) ,
1408
+ } ;
1409
+ // FIXME(eddyb) wrap each promoted type in `MaybeUninit` so that they
1410
+ // don't poison the `largest_niche` or `abi` fields of `prefix`.
1411
+ let promoted_layouts = ineligible_locals. iter ( )
1412
+ . map ( |local| subst_field ( info. field_tys [ local] ) )
1413
+ . map ( |ty| self . layout_of ( ty) ) ;
1414
+ let prefix_layouts = substs. prefix_tys ( def_id, tcx)
1415
+ . map ( |ty| self . layout_of ( ty) )
1416
+ . chain ( iter:: once ( Ok ( discr_layout) ) )
1417
+ . chain ( promoted_layouts)
1418
+ . collect :: < Result < Vec < _ > , _ > > ( ) ?;
1419
+ let mut prefix = self . univariant_uninterned (
1341
1420
ty,
1342
- & prefix_tys . map ( |ty| self . layout_of ( ty ) ) . collect :: < Result < Vec < _ > , _ > > ( ) ? ,
1421
+ & prefix_layouts ,
1343
1422
& ReprOptions :: default ( ) ,
1344
- StructKind :: AlwaysSized ) ?;
1423
+ StructKind :: AlwaysSized ,
1424
+ ) ?;
1425
+ // FIXME(eddyb) need `MaybeUninit` around promoted types (see above).
1426
+ prefix. largest_niche = None ;
1427
+
1345
1428
let ( prefix_size, prefix_align) = ( prefix. size , prefix. align ) ;
1346
1429
1347
1430
// Split the prefix layout into the "outer" fields (upvars and
@@ -1463,10 +1546,6 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
1463
1546
} else {
1464
1547
Abi :: Aggregate { sized : true }
1465
1548
} ;
1466
- let discr = match & self . layout_of ( substs. discr_ty ( tcx) ) ?. abi {
1467
- Abi :: Scalar ( s) => s. clone ( ) ,
1468
- _ => bug ! ( ) ,
1469
- } ;
1470
1549
1471
1550
let layout = tcx. intern_layout ( LayoutDetails {
1472
1551
variants : Variants :: Multiple {
@@ -1477,6 +1556,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
1477
1556
} ,
1478
1557
fields : outer_fields,
1479
1558
abi,
1559
+ largest_niche : prefix. largest_niche ,
1480
1560
size,
1481
1561
align,
1482
1562
} ) ;
@@ -1950,6 +2030,7 @@ where
1950
2030
variants : Variants :: Single { index : variant_index } ,
1951
2031
fields : FieldPlacement :: Union ( fields) ,
1952
2032
abi : Abi :: Uninhabited ,
2033
+ largest_niche : None ,
1953
2034
align : tcx. data_layout . i8_align ,
1954
2035
size : Size :: ZERO
1955
2036
} )
@@ -2222,83 +2303,6 @@ where
2222
2303
}
2223
2304
}
2224
2305
2225
- impl < ' tcx > LayoutCx < ' tcx , TyCtxt < ' tcx > > {
2226
- /// Find the offset of a niche leaf field, starting from
2227
- /// the given type and recursing through aggregates.
2228
- // FIXME(eddyb) traverse already optimized enums.
2229
- fn find_niche ( & self , layout : TyLayout < ' tcx > ) -> Result < Option < Niche > , LayoutError < ' tcx > > {
2230
- let scalar_niche = |scalar : & Scalar , offset| {
2231
- let niche = Niche { offset, scalar : scalar. clone ( ) } ;
2232
- if niche. available ( self ) > 0 {
2233
- Some ( niche)
2234
- } else {
2235
- None
2236
- }
2237
- } ;
2238
-
2239
- // Locals variables which live across yields are stored
2240
- // in the generator type as fields. These may be uninitialized
2241
- // so we don't look for niches there.
2242
- if let ty:: Generator ( ..) = layout. ty . sty {
2243
- return Ok ( None ) ;
2244
- }
2245
-
2246
- match layout. abi {
2247
- Abi :: Scalar ( ref scalar) => {
2248
- return Ok ( scalar_niche ( scalar, Size :: ZERO ) ) ;
2249
- }
2250
- Abi :: ScalarPair ( ref a, ref b) => {
2251
- // HACK(nox): We iter on `b` and then `a` because `max_by_key`
2252
- // returns the last maximum.
2253
- let niche = iter:: once (
2254
- ( b, a. value . size ( self ) . align_to ( b. value . align ( self ) . abi ) )
2255
- )
2256
- . chain ( iter:: once ( ( a, Size :: ZERO ) ) )
2257
- . filter_map ( |( scalar, offset) | scalar_niche ( scalar, offset) )
2258
- . max_by_key ( |niche| niche. available ( self ) ) ;
2259
- return Ok ( niche) ;
2260
- }
2261
- Abi :: Vector { ref element, .. } => {
2262
- return Ok ( scalar_niche ( element, Size :: ZERO ) ) ;
2263
- }
2264
- _ => { }
2265
- }
2266
-
2267
- // Perhaps one of the fields is non-zero, let's recurse and find out.
2268
- if let FieldPlacement :: Union ( _) = layout. fields {
2269
- // Only Rust enums have safe-to-inspect fields
2270
- // (a discriminant), other unions are unsafe.
2271
- if let Variants :: Single { .. } = layout. variants {
2272
- return Ok ( None ) ;
2273
- }
2274
- }
2275
- if let FieldPlacement :: Array { count : original_64_bit_count, .. } = layout. fields {
2276
- // rust-lang/rust#57038: avoid ICE within FieldPlacement::count when count too big
2277
- if original_64_bit_count > usize:: max_value ( ) as u64 {
2278
- return Err ( LayoutError :: SizeOverflow ( layout. ty ) ) ;
2279
- }
2280
- if layout. fields . count ( ) > 0 {
2281
- return self . find_niche ( layout. field ( self , 0 ) ?) ;
2282
- } else {
2283
- return Ok ( None ) ;
2284
- }
2285
- }
2286
- let mut niche = None ;
2287
- let mut available = 0 ;
2288
- for i in 0 ..layout. fields . count ( ) {
2289
- if let Some ( mut c) = self . find_niche ( layout. field ( self , i) ?) ? {
2290
- let c_available = c. available ( self ) ;
2291
- if c_available > available {
2292
- available = c_available;
2293
- c. offset += layout. fields . offset ( i) ;
2294
- niche = Some ( c) ;
2295
- }
2296
- }
2297
- }
2298
- Ok ( niche)
2299
- }
2300
- }
2301
-
2302
2306
impl < ' a > HashStable < StableHashingContext < ' a > > for Variants {
2303
2307
fn hash_stable < W : StableHasherResult > ( & self ,
2304
2308
hcx : & mut StableHashingContext < ' a > ,
@@ -2419,10 +2423,16 @@ impl<'a> HashStable<StableHashingContext<'a>> for Scalar {
2419
2423
}
2420
2424
}
2421
2425
2426
+ impl_stable_hash_for ! ( struct crate :: ty:: layout:: Niche {
2427
+ offset,
2428
+ scalar
2429
+ } ) ;
2430
+
2422
2431
impl_stable_hash_for ! ( struct crate :: ty:: layout:: LayoutDetails {
2423
2432
variants,
2424
2433
fields,
2425
2434
abi,
2435
+ largest_niche,
2426
2436
size,
2427
2437
align
2428
2438
} ) ;
0 commit comments