@@ -57,48 +57,54 @@ pub trait LayoutCalculator {
57
57
// run and bias niches to the right and then check which one is closer to one of the struct's
58
58
// edges.
59
59
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
+ }
102
108
}
103
109
}
104
110
}
@@ -828,6 +834,7 @@ fn univariant(
828
834
if optimize && fields. len ( ) > 1 {
829
835
let end = if let StructKind :: MaybeUnsized = kind { fields. len ( ) - 1 } else { fields. len ( ) } ;
830
836
let optimizing = & mut inverse_memory_index. raw [ ..end] ;
837
+ let fields_excluding_tail = & fields. raw [ ..end] ;
831
838
832
839
// If `-Z randomize-layout` was enabled for the type definition we can shuffle
833
840
// the field ordering to try and catch some code making assumptions about layouts
@@ -844,8 +851,11 @@ fn univariant(
844
851
}
845
852
// Otherwise we just leave things alone and actually optimize the type's fields
846
853
} 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
849
859
. iter ( )
850
860
. filter_map ( |f| f. largest_niche ( ) )
851
861
. map ( |n| n. available ( dl) )
0 commit comments