@@ -283,6 +283,23 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
283
283
284
284
let mut align = if pack. is_some ( ) { dl. i8_align } else { dl. aggregate_align } ;
285
285
286
+ let largest_niche_index = if matches ! ( kind, StructKind :: Prefixed { ..} ) || repr. hide_niche ( ) {
287
+ None
288
+ } else {
289
+ fields
290
+ . iter ( )
291
+ . enumerate ( )
292
+ . filter_map ( |( i, & field) | field. largest_niche . as_ref ( ) . map ( |n| ( i, n) ) )
293
+ . max_by_key ( |( _, niche) | ( niche. available ( dl) , cmp:: Reverse ( niche. offset ) ) )
294
+ . map ( |( i, _) | i as u32 )
295
+ } ;
296
+
297
+ // inverse_memory_index holds field indices by increasing memory offset.
298
+ // That is, if field 5 has offset 0, the first element of inverse_memory_index is 5.
299
+ // We now write field offsets to the corresponding offset slot;
300
+ // field 5 with offset 0 puts 0 in offsets[5].
301
+ // At the bottom of this function, we invert `inverse_memory_index` to
302
+ // produce `memory_index` (see `invert_mapping`).
286
303
let mut inverse_memory_index: Vec < u32 > = ( 0 ..fields. len ( ) as u32 ) . collect ( ) ;
287
304
288
305
let optimize = !repr. inhibit_struct_field_reordering_opt ( ) ;
@@ -296,10 +313,15 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
296
313
match kind {
297
314
StructKind :: AlwaysSized | StructKind :: MaybeUnsized => {
298
315
optimizing. sort_by_key ( |& x| {
299
- // Place ZSTs first to avoid "interesting offsets",
300
- // especially with only one or two non-ZST fields.
301
316
let f = & fields[ x as usize ] ;
302
- ( !f. is_zst ( ) , cmp:: Reverse ( field_align ( f) ) )
317
+ (
318
+ // Place ZSTs first to avoid "interesting offsets",
319
+ // especially with only one or two non-ZST fields.
320
+ !f. is_zst ( ) ,
321
+ cmp:: Reverse ( field_align ( f) ) ,
322
+ // Try to put the largest niche earlier.
323
+ Some ( x) != largest_niche_index,
324
+ )
303
325
} ) ;
304
326
}
305
327
StructKind :: Prefixed ( ..) => {
@@ -308,20 +330,25 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
308
330
optimizing. sort_by_key ( |& x| field_align ( & fields[ x as usize ] ) ) ;
309
331
}
310
332
}
333
+ // Rotate index array to put the largest niche first.
334
+ // Since it is already the first amongst the types with the same alignement,
335
+ // this will just move some of the potential padding within the structure.
336
+ if let ( Some ( niche_index) , StructKind :: AlwaysSized ) = ( largest_niche_index, kind) {
337
+ // ZSTs are always first, and the largest niche is not one, so we can unwrap
338
+ let first_non_zst = inverse_memory_index
339
+ . iter ( )
340
+ . position ( |& x| !fields[ x as usize ] . is_zst ( ) )
341
+ . unwrap ( ) ;
342
+ let non_zsts = & mut inverse_memory_index[ first_non_zst..] ;
343
+ let pivot = non_zsts. iter ( ) . position ( |& x| x == niche_index) . unwrap ( ) ;
344
+ non_zsts. rotate_left ( pivot) ;
345
+ }
311
346
}
312
347
313
- // inverse_memory_index holds field indices by increasing memory offset.
314
- // That is, if field 5 has offset 0, the first element of inverse_memory_index is 5.
315
- // We now write field offsets to the corresponding offset slot;
316
- // field 5 with offset 0 puts 0 in offsets[5].
317
- // At the bottom of this function, we invert `inverse_memory_index` to
318
- // produce `memory_index` (see `invert_mapping`).
319
-
320
348
let mut sized = true ;
321
349
let mut offsets = vec ! [ Size :: ZERO ; fields. len( ) ] ;
322
350
let mut offset = Size :: ZERO ;
323
351
let mut largest_niche = None ;
324
- let mut largest_niche_available = 0 ;
325
352
326
353
if let StructKind :: Prefixed ( prefix_size, prefix_align) = kind {
327
354
let prefix_align =
@@ -351,18 +378,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
351
378
352
379
debug ! ( "univariant offset: {:?} field: {:#?}" , offset, field) ;
353
380
offsets[ i as usize ] = offset;
354
-
355
- if !repr. hide_niche ( ) {
356
- if let Some ( mut niche) = field. largest_niche . clone ( ) {
357
- let available = niche. available ( dl) ;
358
- if available > largest_niche_available {
359
- largest_niche_available = available;
360
- niche. offset += offset;
361
- largest_niche = Some ( niche) ;
362
- }
363
- }
381
+ if largest_niche_index == Some ( i) {
382
+ let mut niche = field. largest_niche . clone ( ) . unwrap ( ) ;
383
+ niche. offset += offset;
384
+ largest_niche = Some ( niche)
364
385
}
365
-
366
386
offset = offset. checked_add ( field. size , dl) . ok_or ( LayoutError :: SizeOverflow ( ty) ) ?;
367
387
}
368
388
0 commit comments