@@ -425,8 +425,19 @@ fn layout_of_uncached<'tcx>(
425425 ) ) ;
426426 }
427427
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 (
430441 & def. repr ( ) ,
431442 & variants,
432443 def. is_enum ( ) ,
@@ -442,21 +453,67 @@ fn layout_of_uncached<'tcx>(
442453 . variants ( )
443454 . iter_enumerated ( )
444455 . 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,
457457 )
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)
460517 }
461518
462519 // Types with no meaningful known layout.
0 commit comments