@@ -90,9 +90,9 @@ fn layout_of<'tcx>(
90
90
let cx = LayoutCx { tcx, param_env } ;
91
91
let layout = layout_of_uncached ( & cx, ty) ?;
92
92
93
- if !naive. is_underestimate_of ( layout) {
93
+ if !naive. is_compatible_with ( layout) {
94
94
bug ! (
95
- "the estimated naive layout is bigger than the actual layout:\n {:#?}\n {:#?}" ,
95
+ "the naive layout isn't compatible with the actual layout:\n {:#?}\n {:#?}" ,
96
96
naive,
97
97
layout,
98
98
) ;
@@ -119,15 +119,23 @@ fn naive_layout_of_uncached<'tcx>(
119
119
let tcx = cx. tcx ;
120
120
let dl = cx. data_layout ( ) ;
121
121
122
- let scalar =
123
- |value : Primitive | NaiveLayout { min_size : value. size ( dl) , min_align : value. align ( dl) . abi } ;
122
+ let scalar = |value : Primitive | NaiveLayout {
123
+ min_size : value. size ( dl) ,
124
+ min_align : value. align ( dl) . abi ,
125
+ is_exact : true ,
126
+ } ;
124
127
125
128
let univariant = |fields : & mut dyn Iterator < Item = Ty < ' tcx > > ,
126
129
repr : & ReprOptions |
127
130
-> Result < NaiveLayout , & ' tcx LayoutError < ' tcx > > {
131
+ if repr. pack . is_some ( ) && repr. align . is_some ( ) {
132
+ cx. tcx . sess . delay_span_bug ( DUMMY_SP , "struct cannot be packed and aligned" ) ;
133
+ return Err ( error ( cx, LayoutError :: Unknown ( ty) ) ) ;
134
+ }
135
+
128
136
// For simplicity, ignore inter-field padding; this may underestimate the size.
129
137
// FIXME(reference_niches): Be smarter and implement something closer to the real layout logic.
130
- let mut layout = NaiveLayout :: EMPTY ;
138
+ let mut layout = NaiveLayout :: UNKNOWN ;
131
139
for field in fields {
132
140
let field = cx. naive_layout_of ( field) ?;
133
141
layout = layout
@@ -192,20 +200,22 @@ fn naive_layout_of_uncached<'tcx>(
192
200
. min_size
193
201
. checked_mul ( count, cx)
194
202
. ok_or_else ( || error ( cx, LayoutError :: SizeOverflow ( ty) ) ) ?,
195
- min_align : element . min_align ,
203
+ .. * element
196
204
}
197
205
}
198
- ty:: Slice ( element) => {
199
- NaiveLayout { min_size : Size :: ZERO , min_align : cx. naive_layout_of ( element) ?. min_align }
200
- }
206
+ ty:: Slice ( element) => NaiveLayout {
207
+ min_size : Size :: ZERO ,
208
+ // NOTE: this could be unconditionally exact if `NaiveLayout` guaranteed exact align.
209
+ ..* cx. naive_layout_of ( element) ?
210
+ } ,
201
211
ty:: Str => NaiveLayout :: EMPTY ,
202
212
203
213
// Odd unit types.
204
214
ty:: FnDef ( ..) | ty:: Dynamic ( _, _, ty:: Dyn ) | ty:: Foreign ( ..) => NaiveLayout :: EMPTY ,
205
215
206
216
// FIXME(reference_niches): try to actually compute a reasonable layout estimate,
207
217
// without duplicating too much code from `generator_layout`.
208
- ty:: Generator ( ..) => NaiveLayout :: EMPTY ,
218
+ ty:: Generator ( ..) => NaiveLayout :: UNKNOWN ,
209
219
210
220
ty:: Closure ( _, ref substs) => {
211
221
univariant ( & mut substs. as_closure ( ) . upvar_tys ( ) , & ReprOptions :: default ( ) ) ?
@@ -223,12 +233,21 @@ fn naive_layout_of_uncached<'tcx>(
223
233
}
224
234
225
235
ty:: Adt ( def, substs) => {
226
- // For simplicity, assume that any discriminant field (if it exists)
227
- // gets niched inside one of the variants; this will underestimate the size
228
- // (and sometimes alignment) of enums.
229
- // FIXME(reference_niches): Be smarter and actually take into accoount the discriminant.
230
236
let repr = def. repr ( ) ;
231
- def. variants ( ) . iter ( ) . try_fold ( NaiveLayout :: EMPTY , |layout, v| {
237
+ let base = if def. is_struct ( ) && !repr. simd ( ) {
238
+ // FIXME(reference_niches): compute proper alignment for SIMD types.
239
+ NaiveLayout :: EMPTY
240
+ } else {
241
+ // For simplicity, assume that any discriminant field (if it exists)
242
+ // gets niched inside one of the variants; this will underestimate the size
243
+ // (and sometimes alignment) of enums.
244
+ // FIXME(reference_niches): Be smarter and actually take into accoount the discriminant.
245
+ // Also consider adding a special case for null-optimized enums, so that we can have
246
+ // `Option<&T>: PointerLike` in generic contexts.
247
+ NaiveLayout :: UNKNOWN
248
+ } ;
249
+
250
+ def. variants ( ) . iter ( ) . try_fold ( base, |layout, v| {
232
251
let mut fields = v. fields . iter ( ) . map ( |f| f. ty ( tcx, substs) ) ;
233
252
let vlayout = univariant ( & mut fields, & repr) ?;
234
253
Ok ( layout. union ( & vlayout) )
@@ -260,12 +279,10 @@ fn univariant_uninterned<'tcx>(
260
279
kind : StructKind ,
261
280
) -> Result < LayoutS , & ' tcx LayoutError < ' tcx > > {
262
281
let dl = cx. data_layout ( ) ;
263
- let pack = repr. pack ;
264
- if pack. is_some ( ) && repr. align . is_some ( ) {
265
- cx. tcx . sess . delay_span_bug ( DUMMY_SP , "struct cannot be packed and aligned" ) ;
266
- return Err ( cx. tcx . arena . alloc ( LayoutError :: Unknown ( ty) ) ) ;
267
- }
268
-
282
+ assert ! (
283
+ !( repr. pack. is_some( ) && repr. align. is_some( ) ) ,
284
+ "already rejected by `naive_layout_of`"
285
+ ) ;
269
286
cx. univariant ( dl, fields, repr, kind) . ok_or_else ( || error ( cx, LayoutError :: SizeOverflow ( ty) ) )
270
287
}
271
288
@@ -325,17 +342,7 @@ fn layout_of_uncached<'tcx>(
325
342
if !ty. is_unsafe_ptr ( ) {
326
343
// Calling `layout_of` here would cause a query cycle for recursive types;
327
344
// so use a conservative estimate that doesn't look past references.
328
- let naive = match cx. naive_layout_of ( pointee) {
329
- Ok ( n) => n. layout ,
330
- // This can happen when computing the `SizeSkeleton` of a generic type.
331
- Err ( LayoutError :: Unknown ( _) ) => {
332
- // TODO(reference_niches): this is *very* incorrect, but we can't
333
- // return an error here; this would break transmute checks.
334
- // We need some other solution.
335
- NaiveLayout :: EMPTY
336
- }
337
- Err ( err) => return Err ( err) ,
338
- } ;
345
+ let naive = cx. naive_layout_of ( pointee) ?. layout ;
339
346
340
347
let niches = match * pointee. kind ( ) {
341
348
ty:: FnDef ( def, ..)
0 commit comments