@@ -463,38 +463,85 @@ fn layout_of_uncached<'tcx>(
463463 ) ) ;
464464 }
465465
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 (
468512 & def. repr ( ) ,
469513 & variants,
470514 def. is_enum ( ) ,
471515 def. is_unsafe_cell ( ) ,
472516 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)
498545 }
499546
500547 // Types with no meaningful known layout.
0 commit comments