@@ -2,7 +2,10 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
2
2
use crate :: mir:: { GeneratorLayout , GeneratorSavedLocal } ;
3
3
use crate :: ty:: normalize_erasing_regions:: NormalizationError ;
4
4
use crate :: ty:: subst:: Subst ;
5
- use crate :: ty:: { self , subst:: SubstsRef , EarlyBinder , ReprOptions , Ty , TyCtxt , TypeVisitable } ;
5
+ use crate :: ty:: {
6
+ self , layout_sanity_check:: sanity_check_layout, subst:: SubstsRef , EarlyBinder , ReprOptions , Ty ,
7
+ TyCtxt , TypeVisitable ,
8
+ } ;
6
9
use rustc_ast as ast;
7
10
use rustc_attr as attr;
8
11
use rustc_hir as hir;
@@ -221,295 +224,6 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
221
224
}
222
225
}
223
226
224
- /// Enforce some basic invariants on layouts.
225
- fn sanity_check_layout < ' tcx > ( cx : & LayoutCx < ' tcx , TyCtxt < ' tcx > > , layout : & TyAndLayout < ' tcx > ) {
226
- // Type-level uninhabitedness should always imply ABI uninhabitedness.
227
- if cx. tcx . conservative_is_privately_uninhabited ( cx. param_env . and ( layout. ty ) ) {
228
- assert ! ( layout. abi. is_uninhabited( ) ) ;
229
- }
230
-
231
- if layout. size . bytes ( ) % layout. align . abi . bytes ( ) != 0 {
232
- bug ! ( "size is not a multiple of align, in the following layout:\n {layout:#?}" ) ;
233
- }
234
-
235
- if cfg ! ( debug_assertions) {
236
- /// Yields non-1-ZST fields of the type
237
- fn non_zst_fields < ' tcx , ' a > (
238
- cx : & ' a LayoutCx < ' tcx , TyCtxt < ' tcx > > ,
239
- layout : & ' a TyAndLayout < ' tcx > ,
240
- ) -> impl Iterator < Item = ( Size , TyAndLayout < ' tcx > ) > + ' a {
241
- ( 0 ..layout. layout . fields ( ) . count ( ) ) . filter_map ( |i| {
242
- let field = layout. field ( cx, i) ;
243
- // Also checking `align == 1` here leads to test failures in
244
- // `layout/zero-sized-array-union.rs`, where a type has a zero-size field with
245
- // alignment 4 that still gets ignored during layout computation (which is okay
246
- // since other fields already force alignment 4).
247
- let zst = field. is_zst ( ) ;
248
- ( !zst) . then ( || ( layout. fields . offset ( i) , field) )
249
- } )
250
- }
251
-
252
- fn skip_newtypes < ' tcx > (
253
- cx : & LayoutCx < ' tcx , TyCtxt < ' tcx > > ,
254
- layout : & TyAndLayout < ' tcx > ,
255
- ) -> TyAndLayout < ' tcx > {
256
- if matches ! ( layout. layout. variants( ) , Variants :: Multiple { .. } ) {
257
- // Definitely not a newtype of anything.
258
- return * layout;
259
- }
260
- let mut fields = non_zst_fields ( cx, layout) ;
261
- let Some ( first) = fields. next ( ) else {
262
- // No fields here, so this could be a primitive or enum -- either way it's not a newtype around a thing
263
- return * layout
264
- } ;
265
- if fields. next ( ) . is_none ( ) {
266
- let ( offset, first) = first;
267
- if offset == Size :: ZERO && first. layout . size ( ) == layout. size {
268
- // This is a newtype, so keep recursing.
269
- // FIXME(RalfJung): I don't think it would be correct to do any checks for
270
- // alignment here, so we don't. Is that correct?
271
- return skip_newtypes ( cx, & first) ;
272
- }
273
- }
274
- // No more newtypes here.
275
- * layout
276
- }
277
-
278
- fn check_layout_abi < ' tcx > ( cx : & LayoutCx < ' tcx , TyCtxt < ' tcx > > , layout : & TyAndLayout < ' tcx > ) {
279
- match layout. layout . abi ( ) {
280
- Abi :: Scalar ( scalar) => {
281
- // No padding in scalars.
282
- let size = scalar. size ( cx) ;
283
- let align = scalar. align ( cx) . abi ;
284
- assert_eq ! (
285
- layout. layout. size( ) ,
286
- size,
287
- "size mismatch between ABI and layout in {layout:#?}"
288
- ) ;
289
- assert_eq ! (
290
- layout. layout. align( ) . abi,
291
- align,
292
- "alignment mismatch between ABI and layout in {layout:#?}"
293
- ) ;
294
- // Check that this matches the underlying field.
295
- let inner = skip_newtypes ( cx, layout) ;
296
- assert ! (
297
- matches!( inner. layout. abi( ) , Abi :: Scalar ( _) ) ,
298
- "`Scalar` type {} is newtype around non-`Scalar` type {}" ,
299
- layout. ty,
300
- inner. ty
301
- ) ;
302
- match inner. layout . fields ( ) {
303
- FieldsShape :: Primitive => {
304
- // Fine.
305
- }
306
- FieldsShape :: Arbitrary { .. } => {
307
- // Should be an enum, the only field is the discriminant.
308
- assert ! (
309
- inner. ty. is_enum( ) ,
310
- "`Scalar` layout for non-primitive non-enum type {}" ,
311
- inner. ty
312
- ) ;
313
- assert_eq ! (
314
- inner. layout. fields( ) . count( ) ,
315
- 1 ,
316
- "`Scalar` layout for multiple-field type in {inner:#?}" ,
317
- ) ;
318
- let offset = inner. layout . fields ( ) . offset ( 0 ) ;
319
- let field = inner. field ( cx, 0 ) ;
320
- // The field should be at the right offset, and match the `scalar` layout.
321
- assert_eq ! (
322
- offset,
323
- Size :: ZERO ,
324
- "`Scalar` field at non-0 offset in {inner:#?}" ,
325
- ) ;
326
- assert_eq ! (
327
- field. size, size,
328
- "`Scalar` field with bad size in {inner:#?}" ,
329
- ) ;
330
- assert_eq ! (
331
- field. align. abi, align,
332
- "`Scalar` field with bad align in {inner:#?}" ,
333
- ) ;
334
- assert ! (
335
- matches!( field. abi, Abi :: Scalar ( _) ) ,
336
- "`Scalar` field with bad ABI in {inner:#?}" ,
337
- ) ;
338
- }
339
- _ => {
340
- panic ! ( "`Scalar` layout for non-primitive non-enum type {}" , inner. ty) ;
341
- }
342
- }
343
- }
344
- Abi :: ScalarPair ( scalar1, scalar2) => {
345
- // Sanity-check scalar pairs. These are a bit more flexible and support
346
- // padding, but we can at least ensure both fields actually fit into the layout
347
- // and the alignment requirement has not been weakened.
348
- let size1 = scalar1. size ( cx) ;
349
- let align1 = scalar1. align ( cx) . abi ;
350
- let size2 = scalar2. size ( cx) ;
351
- let align2 = scalar2. align ( cx) . abi ;
352
- assert ! (
353
- layout. layout. align( ) . abi >= cmp:: max( align1, align2) ,
354
- "alignment mismatch between ABI and layout in {layout:#?}" ,
355
- ) ;
356
- let field2_offset = size1. align_to ( align2) ;
357
- assert ! (
358
- layout. layout. size( ) >= field2_offset + size2,
359
- "size mismatch between ABI and layout in {layout:#?}"
360
- ) ;
361
- // Check that the underlying pair of fields matches.
362
- let inner = skip_newtypes ( cx, layout) ;
363
- assert ! (
364
- matches!( inner. layout. abi( ) , Abi :: ScalarPair ( ..) ) ,
365
- "`ScalarPair` type {} is newtype around non-`ScalarPair` type {}" ,
366
- layout. ty,
367
- inner. ty
368
- ) ;
369
- if matches ! ( inner. layout. variants( ) , Variants :: Multiple { .. } ) {
370
- // FIXME: ScalarPair for enums is enormously complicated and it is very hard
371
- // to check anything about them.
372
- return ;
373
- }
374
- match inner. layout . fields ( ) {
375
- FieldsShape :: Arbitrary { .. } => {
376
- // Checked below.
377
- }
378
- FieldsShape :: Union ( ..) => {
379
- // FIXME: I guess we could also check something here? Like, look at all fields?
380
- return ;
381
- }
382
- _ => {
383
- panic ! ( "`ScalarPair` layout with unexpected field shape in {inner:#?}" ) ;
384
- }
385
- }
386
- let mut fields = non_zst_fields ( cx, & inner) ;
387
- let ( offset1, field1) = fields. next ( ) . unwrap_or_else ( || {
388
- panic ! ( "`ScalarPair` layout for type with not even one non-ZST field: {inner:#?}" )
389
- } ) ;
390
- let ( offset2, field2) = fields. next ( ) . unwrap_or_else ( || {
391
- panic ! ( "`ScalarPair` layout for type with less than two non-ZST fields: {inner:#?}" )
392
- } ) ;
393
- assert ! (
394
- fields. next( ) . is_none( ) ,
395
- "`ScalarPair` layout for type with at least three non-ZST fields: {inner:#?}"
396
- ) ;
397
- // The fields might be in opposite order.
398
- let ( offset1, field1, offset2, field2) = if offset1 <= offset2 {
399
- ( offset1, field1, offset2, field2)
400
- } else {
401
- ( offset2, field2, offset1, field1)
402
- } ;
403
- // The fields should be at the right offset, and match the `scalar` layout.
404
- assert_eq ! (
405
- offset1,
406
- Size :: ZERO ,
407
- "`ScalarPair` first field at non-0 offset in {inner:#?}" ,
408
- ) ;
409
- assert_eq ! (
410
- field1. size, size1,
411
- "`ScalarPair` first field with bad size in {inner:#?}" ,
412
- ) ;
413
- assert_eq ! (
414
- field1. align. abi, align1,
415
- "`ScalarPair` first field with bad align in {inner:#?}" ,
416
- ) ;
417
- assert ! (
418
- matches!( field1. abi, Abi :: Scalar ( _) ) ,
419
- "`ScalarPair` first field with bad ABI in {inner:#?}" ,
420
- ) ;
421
- assert_eq ! (
422
- offset2, field2_offset,
423
- "`ScalarPair` second field at bad offset in {inner:#?}" ,
424
- ) ;
425
- assert_eq ! (
426
- field2. size, size2,
427
- "`ScalarPair` second field with bad size in {inner:#?}" ,
428
- ) ;
429
- assert_eq ! (
430
- field2. align. abi, align2,
431
- "`ScalarPair` second field with bad align in {inner:#?}" ,
432
- ) ;
433
- assert ! (
434
- matches!( field2. abi, Abi :: Scalar ( _) ) ,
435
- "`ScalarPair` second field with bad ABI in {inner:#?}" ,
436
- ) ;
437
- }
438
- Abi :: Vector { count, element } => {
439
- // No padding in vectors. Alignment can be strengthened, though.
440
- assert ! (
441
- layout. layout. align( ) . abi >= element. align( cx) . abi,
442
- "alignment mismatch between ABI and layout in {layout:#?}"
443
- ) ;
444
- let size = element. size ( cx) * count;
445
- assert_eq ! (
446
- layout. layout. size( ) ,
447
- size. align_to( cx. data_layout( ) . vector_align( size) . abi) ,
448
- "size mismatch between ABI and layout in {layout:#?}"
449
- ) ;
450
- }
451
- Abi :: Uninhabited | Abi :: Aggregate { .. } => { } // Nothing to check.
452
- }
453
- }
454
-
455
- check_layout_abi ( cx, layout) ;
456
-
457
- if let Variants :: Multiple { variants, .. } = & layout. variants {
458
- for variant in variants. iter ( ) {
459
- // No nested "multiple".
460
- assert ! ( matches!( variant. variants( ) , Variants :: Single { .. } ) ) ;
461
- // Variants should have the same or a smaller size as the full thing,
462
- // and same for alignment.
463
- if variant. size ( ) > layout. size {
464
- bug ! (
465
- "Type with size {} bytes has variant with size {} bytes: {layout:#?}" ,
466
- layout. size. bytes( ) ,
467
- variant. size( ) . bytes( ) ,
468
- )
469
- }
470
- if variant. align ( ) . abi > layout. align . abi {
471
- bug ! (
472
- "Type with alignment {} bytes has variant with alignment {} bytes: {layout:#?}" ,
473
- layout. align. abi. bytes( ) ,
474
- variant. align( ) . abi. bytes( ) ,
475
- )
476
- }
477
- // Skip empty variants.
478
- if variant. size ( ) == Size :: ZERO
479
- || variant. fields ( ) . count ( ) == 0
480
- || variant. abi ( ) . is_uninhabited ( )
481
- {
482
- // These are never actually accessed anyway, so we can skip the coherence check
483
- // for them. They also fail that check, since they have
484
- // `Aggregate`/`Uninhbaited` ABI even when the main type is
485
- // `Scalar`/`ScalarPair`. (Note that sometimes, variants with fields have size
486
- // 0, and sometimes, variants without fields have non-0 size.)
487
- continue ;
488
- }
489
- // The top-level ABI and the ABI of the variants should be coherent.
490
- let scalar_coherent = |s1 : Scalar , s2 : Scalar | {
491
- s1. size ( cx) == s2. size ( cx) && s1. align ( cx) == s2. align ( cx)
492
- } ;
493
- let abi_coherent = match ( layout. abi , variant. abi ( ) ) {
494
- ( Abi :: Scalar ( s1) , Abi :: Scalar ( s2) ) => scalar_coherent ( s1, s2) ,
495
- ( Abi :: ScalarPair ( a1, b1) , Abi :: ScalarPair ( a2, b2) ) => {
496
- scalar_coherent ( a1, a2) && scalar_coherent ( b1, b2)
497
- }
498
- ( Abi :: Uninhabited , _) => true ,
499
- ( Abi :: Aggregate { .. } , _) => true ,
500
- _ => false ,
501
- } ;
502
- if !abi_coherent {
503
- bug ! (
504
- "Variant ABI is incompatible with top-level ABI:\n variant={:#?}\n Top-level: {layout:#?}" ,
505
- variant
506
- ) ;
507
- }
508
- }
509
- }
510
- }
511
- }
512
-
513
227
#[ instrument( skip( tcx, query) , level = "debug" ) ]
514
228
fn layout_of < ' tcx > (
515
229
tcx : TyCtxt < ' tcx > ,
0 commit comments