@@ -463,38 +463,85 @@ fn layout_of_uncached<'tcx>(
463
463
) ) ;
464
464
}
465
465
466
- tcx. mk_layout (
467
- cx. layout_of_struct_or_enum (
466
+ let get_discriminant_type =
467
+ |min, max| Integer :: repr_discr ( tcx, ty, & def. repr ( ) , min, max) ;
468
+
469
+ let discriminants_iter = || {
470
+ def. is_enum ( )
471
+ . then ( || def. discriminants ( tcx) . map ( |( v, d) | ( v, d. val as i128 ) ) )
472
+ . into_iter ( )
473
+ . flatten ( )
474
+ } ;
475
+
476
+ let dont_niche_optimize_enum = def. repr ( ) . inhibit_enum_layout_opt ( )
477
+ || def
478
+ . variants ( )
479
+ . iter_enumerated ( )
480
+ . any ( |( i, v) | v. discr != ty:: VariantDiscr :: Relative ( i. as_u32 ( ) ) ) ;
481
+
482
+ let maybe_unsized = def. is_struct ( )
483
+ && def. non_enum_variant ( ) . tail_opt ( ) . is_some_and ( |last_field| {
484
+ let param_env = tcx. param_env ( def. did ( ) ) ;
485
+ !tcx. type_of ( last_field. did ) . subst_identity ( ) . is_sized ( tcx, param_env)
486
+ } ) ;
487
+
488
+ let Some ( layout) = cx. layout_of_struct_or_enum (
489
+ & def. repr ( ) ,
490
+ & variants,
491
+ def. is_enum ( ) ,
492
+ def. is_unsafe_cell ( ) ,
493
+ tcx. layout_scalar_valid_range ( def. did ( ) ) ,
494
+ get_discriminant_type,
495
+ discriminants_iter ( ) ,
496
+ dont_niche_optimize_enum,
497
+ !maybe_unsized,
498
+ ) else {
499
+ return Err ( error ( cx, LayoutError :: SizeOverflow ( ty) ) ) ;
500
+ } ;
501
+
502
+ // If the struct tail is sized and can be unsized, check that unsizing doesn't move the fields around.
503
+ if cfg ! ( debug_assertions)
504
+ && maybe_unsized
505
+ && def. non_enum_variant ( ) . tail ( ) . ty ( tcx, substs) . is_sized ( tcx, cx. param_env )
506
+ {
507
+ let mut variants = variants;
508
+ let tail_replacement = cx. layout_of ( Ty :: new_slice ( tcx, tcx. types . u8 ) ) . unwrap ( ) ;
509
+ * variants[ FIRST_VARIANT ] . raw . last_mut ( ) . unwrap ( ) = tail_replacement. layout ;
510
+
511
+ let Some ( unsized_layout) = cx. layout_of_struct_or_enum (
468
512
& def. repr ( ) ,
469
513
& variants,
470
514
def. is_enum ( ) ,
471
515
def. is_unsafe_cell ( ) ,
472
516
tcx. layout_scalar_valid_range ( def. did ( ) ) ,
473
- |min, max| Integer :: repr_discr ( tcx, ty, & def. repr ( ) , min, max) ,
474
- def. is_enum ( )
475
- . then ( || def. discriminants ( tcx) . map ( |( v, d) | ( v, d. val as i128 ) ) )
476
- . into_iter ( )
477
- . flatten ( ) ,
478
- def. repr ( ) . inhibit_enum_layout_opt ( )
479
- || def
480
- . variants ( )
481
- . iter_enumerated ( )
482
- . any ( |( i, v) | v. discr != ty:: VariantDiscr :: Relative ( i. as_u32 ( ) ) ) ,
483
- {
484
- let param_env = tcx. param_env ( def. did ( ) ) ;
485
- def. is_struct ( )
486
- && match def. variants ( ) . iter ( ) . next ( ) . and_then ( |x| x. fields . raw . last ( ) )
487
- {
488
- Some ( last_field) => tcx
489
- . type_of ( last_field. did )
490
- . subst_identity ( )
491
- . is_sized ( tcx, param_env) ,
492
- None => false ,
493
- }
494
- } ,
495
- )
496
- . ok_or_else ( || error ( cx, LayoutError :: SizeOverflow ( ty) ) ) ?,
497
- )
517
+ get_discriminant_type,
518
+ discriminants_iter ( ) ,
519
+ dont_niche_optimize_enum,
520
+ !maybe_unsized,
521
+ ) else {
522
+ bug ! ( "failed to compute unsized layout of {ty:?}" ) ;
523
+ } ;
524
+
525
+ let FieldsShape :: Arbitrary { offsets : sized_offsets, .. } = & layout. fields else {
526
+ bug ! ( "unexpected FieldsShape for sized layout of {ty:?}: {:?}" , layout. fields) ;
527
+ } ;
528
+ let FieldsShape :: Arbitrary { offsets : unsized_offsets, .. } = & unsized_layout. fields else {
529
+ bug ! ( "unexpected FieldsShape for unsized layout of {ty:?}: {:?}" , unsized_layout. fields) ;
530
+ } ;
531
+
532
+ let ( sized_tail, sized_fields) = sized_offsets. raw . split_last ( ) . unwrap ( ) ;
533
+ let ( unsized_tail, unsized_fields) = unsized_offsets. raw . split_last ( ) . unwrap ( ) ;
534
+
535
+ if sized_fields != unsized_fields {
536
+ bug ! ( "unsizing {ty:?} changed field order!\n {layout:?}\n {unsized_layout:?}" ) ;
537
+ }
538
+
539
+ if sized_tail < unsized_tail {
540
+ bug ! ( "unsizing {ty:?} moved tail backwards!\n {layout:?}\n {unsized_layout:?}" ) ;
541
+ }
542
+ }
543
+
544
+ tcx. mk_layout ( layout)
498
545
}
499
546
500
547
// Types with no meaningful known layout.
0 commit comments