@@ -57,48 +57,54 @@ pub trait LayoutCalculator {
5757 // run and bias niches to the right and then check which one is closer to one of the struct's
5858 // edges.
5959 if let Some ( layout) = & layout {
60- if let Some ( niche) = layout. largest_niche {
61- let head_space = niche. offset . bytes ( ) ;
62- let niche_length = niche. value . size ( dl) . bytes ( ) ;
63- let tail_space = layout. size . bytes ( ) - head_space - niche_length;
64-
65- // This may end up doing redundant work if the niche is already in the last field
66- // (e.g. a trailing bool) and there is tail padding. But it's non-trivial to get
67- // the unpadded size so we try anyway.
68- if fields. len ( ) > 1 && head_space != 0 && tail_space > 0 {
69- let alt_layout = univariant ( self , dl, fields, repr, kind, NicheBias :: End )
70- . expect ( "alt layout should always work" ) ;
71- let niche = alt_layout
72- . largest_niche
73- . expect ( "alt layout should have a niche like the regular one" ) ;
74- let alt_head_space = niche. offset . bytes ( ) ;
75- let alt_niche_len = niche. value . size ( dl) . bytes ( ) ;
76- let alt_tail_space = alt_layout. size . bytes ( ) - alt_head_space - alt_niche_len;
77-
78- debug_assert_eq ! ( layout. size. bytes( ) , alt_layout. size. bytes( ) ) ;
79-
80- let prefer_alt_layout =
81- alt_head_space > head_space && alt_head_space > tail_space;
82-
83- debug ! (
84- "sz: {}, default_niche_at: {}+{}, default_tail_space: {}, alt_niche_at/head_space: {}+{}, alt_tail: {}, num_fields: {}, better: {}\n \
85- layout: {}\n \
86- alt_layout: {}\n ",
87- layout. size. bytes( ) ,
88- head_space,
89- niche_length,
90- tail_space,
91- alt_head_space,
92- alt_niche_len,
93- alt_tail_space,
94- layout. fields. count( ) ,
95- prefer_alt_layout,
96- format_field_niches( & layout, & fields, & dl) ,
97- format_field_niches( & alt_layout, & fields, & dl) ,
98- ) ;
99-
100- if prefer_alt_layout {
101- return Some ( alt_layout) ;
60+ // Don't try to calculate an end-biased layout for unsizable structs,
61+ // otherwise we could end up with different layouts for
62+ // Foo<Type> and Foo<dyn Trait> which would break unsizing
63+ if !matches ! ( kind, StructKind :: MaybeUnsized ) {
64+ if let Some ( niche) = layout. largest_niche {
65+ let head_space = niche. offset . bytes ( ) ;
66+ let niche_length = niche. value . size ( dl) . bytes ( ) ;
67+ let tail_space = layout. size . bytes ( ) - head_space - niche_length;
68+
69+ // This may end up doing redundant work if the niche is already in the last field
70+ // (e.g. a trailing bool) and there is tail padding. But it's non-trivial to get
71+ // the unpadded size so we try anyway.
72+ if fields. len ( ) > 1 && head_space != 0 && tail_space > 0 {
73+ let alt_layout = univariant ( self , dl, fields, repr, kind, NicheBias :: End )
74+ . expect ( "alt layout should always work" ) ;
75+ let niche = alt_layout
76+ . largest_niche
77+ . expect ( "alt layout should have a niche like the regular one" ) ;
78+ let alt_head_space = niche. offset . bytes ( ) ;
79+ let alt_niche_len = niche. value . size ( dl) . bytes ( ) ;
80+ let alt_tail_space =
81+ alt_layout. size . bytes ( ) - alt_head_space - alt_niche_len;
82+
83+ debug_assert_eq ! ( layout. size. bytes( ) , alt_layout. size. bytes( ) ) ;
84+
85+ let prefer_alt_layout =
86+ alt_head_space > head_space && alt_head_space > tail_space;
87+
88+ debug ! (
89+ "sz: {}, default_niche_at: {}+{}, default_tail_space: {}, alt_niche_at/head_space: {}+{}, alt_tail: {}, num_fields: {}, better: {}\n \
90+ layout: {}\n \
91+ alt_layout: {}\n ",
92+ layout. size. bytes( ) ,
93+ head_space,
94+ niche_length,
95+ tail_space,
96+ alt_head_space,
97+ alt_niche_len,
98+ alt_tail_space,
99+ layout. fields. count( ) ,
100+ prefer_alt_layout,
101+ format_field_niches( & layout, & fields, & dl) ,
102+ format_field_niches( & alt_layout, & fields, & dl) ,
103+ ) ;
104+
105+ if prefer_alt_layout {
106+ return Some ( alt_layout) ;
107+ }
102108 }
103109 }
104110 }
@@ -828,6 +834,7 @@ fn univariant(
828834 if optimize && fields. len ( ) > 1 {
829835 let end = if let StructKind :: MaybeUnsized = kind { fields. len ( ) - 1 } else { fields. len ( ) } ;
830836 let optimizing = & mut inverse_memory_index. raw [ ..end] ;
837+ let fields_excluding_tail = & fields. raw [ ..end] ;
831838
832839 // If `-Z randomize-layout` was enabled for the type definition we can shuffle
833840 // the field ordering to try and catch some code making assumptions about layouts
@@ -844,8 +851,11 @@ fn univariant(
844851 }
845852 // Otherwise we just leave things alone and actually optimize the type's fields
846853 } else {
847- let max_field_align = fields. iter ( ) . map ( |f| f. align ( ) . abi . bytes ( ) ) . max ( ) . unwrap_or ( 1 ) ;
848- let largest_niche_size = fields
854+ // To allow unsizing `&Foo<Type>` -> `&Foo<dyn Trait>`, the layout of the struct must
855+ // not depend on the layout of the tail.
856+ let max_field_align =
857+ fields_excluding_tail. iter ( ) . map ( |f| f. align ( ) . abi . bytes ( ) ) . max ( ) . unwrap_or ( 1 ) ;
858+ let largest_niche_size = fields_excluding_tail
849859 . iter ( )
850860 . filter_map ( |f| f. largest_niche ( ) )
851861 . map ( |n| n. available ( dl) )
0 commit comments