@@ -425,8 +425,19 @@ fn layout_of_uncached<'tcx>(
425
425
) ) ;
426
426
}
427
427
428
- tcx. mk_layout (
429
- cx. layout_of_struct_or_enum (
428
+ let always_sized = {
429
+ let param_env = tcx. param_env ( def. did ( ) ) ;
430
+ def. is_struct ( )
431
+ && match def. variants ( ) . iter ( ) . next ( ) . and_then ( |x| x. fields . raw . last ( ) ) {
432
+ Some ( last_field) => {
433
+ tcx. type_of ( last_field. did ) . subst_identity ( ) . is_sized ( tcx, param_env)
434
+ }
435
+ None => false ,
436
+ }
437
+ } ;
438
+
439
+ let layout = cx
440
+ . layout_of_struct_or_enum (
430
441
& def. repr ( ) ,
431
442
& variants,
432
443
def. is_enum ( ) ,
@@ -442,21 +453,67 @@ fn layout_of_uncached<'tcx>(
442
453
. variants ( )
443
454
. iter_enumerated ( )
444
455
. any ( |( i, v) | v. discr != ty:: VariantDiscr :: Relative ( i. as_u32 ( ) ) ) ,
445
- {
446
- let param_env = tcx. param_env ( def. did ( ) ) ;
447
- def. is_struct ( )
448
- && match def. variants ( ) . iter ( ) . next ( ) . and_then ( |x| x. fields . raw . last ( ) )
449
- {
450
- Some ( last_field) => tcx
451
- . type_of ( last_field. did )
452
- . subst_identity ( )
453
- . is_sized ( tcx, param_env) ,
454
- None => false ,
455
- }
456
- } ,
456
+ always_sized,
457
457
)
458
- . ok_or ( LayoutError :: SizeOverflow ( ty) ) ?,
459
- )
458
+ . ok_or ( LayoutError :: SizeOverflow ( ty) ) ?;
459
+
460
+ if def. is_struct ( ) && !always_sized {
461
+ let mut variants_again = variants. clone ( ) ;
462
+
463
+ let mut unit = univariant_uninterned (
464
+ cx,
465
+ ty,
466
+ IndexSlice :: empty ( ) ,
467
+ & ReprOptions :: default ( ) ,
468
+ StructKind :: AlwaysSized ,
469
+ )
470
+ . unwrap ( ) ;
471
+ match unit. abi {
472
+ Abi :: Aggregate { ref mut sized } => * sized = false ,
473
+ _ => bug ! ( ) ,
474
+ }
475
+ let unit_interned = tcx. mk_layout ( unit. clone ( ) ) ;
476
+
477
+ if let Some ( tail) = variants_again[ FIRST_VARIANT ] . raw . last_mut ( ) && * tail. 0 . 0 != unit {
478
+ * tail = unit_interned;
479
+
480
+ let layout_again = cx. layout_of_struct_or_enum (
481
+ & def. repr ( ) ,
482
+ & variants_again,
483
+ def. is_enum ( ) ,
484
+ def. is_unsafe_cell ( ) ,
485
+ tcx. layout_scalar_valid_range ( def. did ( ) ) ,
486
+ |min, max| Integer :: repr_discr ( tcx, ty, & def. repr ( ) , min, max) ,
487
+ def. is_enum ( )
488
+ . then ( || def. discriminants ( tcx) . map ( |( v, d) | ( v, d. val as i128 ) ) )
489
+ . into_iter ( )
490
+ . flatten ( ) ,
491
+ def. repr ( ) . inhibit_enum_layout_opt ( )
492
+ || def
493
+ . variants ( )
494
+ . iter_enumerated ( )
495
+ . any ( |( i, v) | v. discr != ty:: VariantDiscr :: Relative ( i. as_u32 ( ) ) ) ,
496
+ always_sized,
497
+ )
498
+ . unwrap ( ) ;
499
+
500
+ let mut fields1 = layout. fields . clone ( ) ;
501
+ let mut fields2 = layout_again. fields . clone ( ) ;
502
+
503
+ if let FieldsShape :: Arbitrary { offsets : ref mut offsets1, .. } = fields1
504
+ && let FieldsShape :: Arbitrary { offsets : ref mut offsets2, .. } = fields2
505
+ && let Some ( last1) = offsets1. raw . last ( )
506
+ && let Some ( last2) = offsets1. raw . last ( ) {
507
+ assert ! ( last1 >= last2) ;
508
+ offsets1. pop ( ) ;
509
+ offsets2. pop ( ) ;
510
+ }
511
+
512
+ assert_eq ! ( fields1, fields2) ;
513
+ }
514
+ }
515
+
516
+ tcx. mk_layout ( layout)
460
517
}
461
518
462
519
// Types with no meaningful known layout.
0 commit comments