@@ -220,6 +220,91 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
220
220
}
221
221
}
222
222
223
+ /// Enforce some basic invariants on layouts.
224
+ fn sanity_check_layout < ' tcx > (
225
+ tcx : TyCtxt < ' tcx > ,
226
+ param_env : ty:: ParamEnv < ' tcx > ,
227
+ layout : & TyAndLayout < ' tcx > ,
228
+ ) {
229
+ // Type-level uninhabitedness should always imply ABI uninhabitedness.
230
+ if tcx. conservative_is_privately_uninhabited ( param_env. and ( layout. ty ) ) {
231
+ assert ! ( layout. abi. is_uninhabited( ) ) ;
232
+ }
233
+
234
+ if cfg ! ( debug_assertions) {
235
+ fn check_layout_abi < ' tcx > ( tcx : TyCtxt < ' tcx > , layout : Layout < ' tcx > ) {
236
+ match layout. abi ( ) {
237
+ Abi :: Scalar ( _scalar) => {
238
+ // No padding in scalars.
239
+ /* FIXME(#96185):
240
+ assert_eq!(
241
+ layout.align().abi,
242
+ scalar.align(&tcx).abi,
243
+ "alignment mismatch between ABI and layout in {layout:#?}"
244
+ );
245
+ assert_eq!(
246
+ layout.size(),
247
+ scalar.size(&tcx),
248
+ "size mismatch between ABI and layout in {layout:#?}"
249
+ );*/
250
+ }
251
+ Abi :: ScalarPair ( scalar1, scalar2) => {
252
+ // Sanity-check scalar pair size.
253
+ let field2_offset = scalar1. size ( & tcx) . align_to ( scalar2. align ( & tcx) . abi ) ;
254
+ let total = field2_offset + scalar2. size ( & tcx) ;
255
+ assert ! (
256
+ layout. size( ) >= total,
257
+ "size mismatch between ABI and layout in {layout:#?}"
258
+ ) ;
259
+ }
260
+ _ => { }
261
+ }
262
+ }
263
+
264
+ check_layout_abi ( tcx, layout. layout ) ;
265
+
266
+ if let Variants :: Multiple { variants, .. } = & layout. variants {
267
+ for variant in variants {
268
+ check_layout_abi ( tcx, * variant) ;
269
+ // No nested "multiple".
270
+ assert ! ( matches!( variant. variants( ) , Variants :: Single { .. } ) ) ;
271
+ // Skip empty variants.
272
+ if variant. size ( ) == Size :: ZERO
273
+ || variant. fields ( ) . count ( ) == 0
274
+ || variant. abi ( ) . is_uninhabited ( )
275
+ {
276
+ // These are never actually accessed anyway, so we can skip them. (Note that
277
+ // sometimes, variants with fields have size 0, and sometimes, variants without
278
+ // fields have non-0 size.)
279
+ continue ;
280
+ }
281
+ // Variants should have the same or a smaller size as the full thing.
282
+ if variant. size ( ) > layout. size {
283
+ bug ! (
284
+ "Type with size {} bytes has variant with size {} bytes: {layout:#?}" ,
285
+ layout. size. bytes( ) ,
286
+ variant. size( ) . bytes( ) ,
287
+ )
288
+ }
289
+ // The top-level ABI and the ABI of the variants should be coherent.
290
+ let abi_coherent = match ( layout. abi , variant. abi ( ) ) {
291
+ ( Abi :: Scalar ( ..) , Abi :: Scalar ( ..) ) => true ,
292
+ ( Abi :: ScalarPair ( ..) , Abi :: ScalarPair ( ..) ) => true ,
293
+ ( Abi :: Uninhabited , _) => true ,
294
+ ( Abi :: Aggregate { .. } , _) => true ,
295
+ _ => false ,
296
+ } ;
297
+ if !abi_coherent {
298
+ bug ! (
299
+ "Variant ABI is incompatible with top-level ABI:\n variant={:#?}\n Top-level: {layout:#?}" ,
300
+ variant
301
+ ) ;
302
+ }
303
+ }
304
+ }
305
+ }
306
+ }
307
+
223
308
#[ instrument( skip( tcx, query) , level = "debug" ) ]
224
309
fn layout_of < ' tcx > (
225
310
tcx : TyCtxt < ' tcx > ,
@@ -263,10 +348,7 @@ fn layout_of<'tcx>(
263
348
264
349
cx. record_layout_for_printing ( layout) ;
265
350
266
- // Type-level uninhabitedness should always imply ABI uninhabitedness.
267
- if tcx. conservative_is_privately_uninhabited ( param_env. and ( ty) ) {
268
- assert ! ( layout. abi. is_uninhabited( ) ) ;
269
- }
351
+ sanity_check_layout ( tcx, param_env, & layout) ;
270
352
271
353
Ok ( layout)
272
354
} )
@@ -1313,10 +1395,22 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
1313
1395
} ;
1314
1396
let mut abi = Abi :: Aggregate { sized : true } ;
1315
1397
1316
- // Without latter check aligned enums with custom discriminant values
1317
- // Would result in ICE see the issue #92464 for more info
1318
- if tag. size ( dl) == size || variants. iter ( ) . all ( |layout| layout. is_empty ( ) ) {
1398
+ if layout_variants. iter ( ) . all ( |v| v. abi . is_uninhabited ( ) ) {
1399
+ abi = Abi :: Uninhabited ;
1400
+ } else if tag. size ( dl) == size || variants. iter ( ) . all ( |layout| layout. is_empty ( ) ) {
1401
+ // Without latter check aligned enums with custom discriminant values
1402
+ // Would result in ICE see the issue #92464 for more info
1319
1403
abi = Abi :: Scalar ( tag) ;
1404
+ // Make sure the variants with fields have the same ABI as the enum itself
1405
+ // (since downcasting to them is a NOP).
1406
+ for variant in & mut layout_variants {
1407
+ if variant. fields . count ( ) > 0
1408
+ && matches ! ( variant. abi, Abi :: Aggregate { .. } )
1409
+ {
1410
+ assert_eq ! ( variant. size, size) ;
1411
+ variant. abi = abi;
1412
+ }
1413
+ }
1320
1414
} else {
1321
1415
// Try to use a ScalarPair for all tagged enums.
1322
1416
let mut common_prim = None ;
@@ -1385,14 +1479,21 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
1385
1479
// We can use `ScalarPair` only when it matches our
1386
1480
// already computed layout (including `#[repr(C)]`).
1387
1481
abi = pair. abi ;
1482
+ // Make sure the variants with fields have the same ABI as the enum itself
1483
+ // (since downcasting to them is a NOP).
1484
+ for variant in & mut layout_variants {
1485
+ if variant. fields . count ( ) > 0
1486
+ && matches ! ( variant. abi, Abi :: Aggregate { .. } )
1487
+ {
1488
+ variant. abi = abi;
1489
+ // Also need to bump up the size, so that the pair fits inside.
1490
+ variant. size = size;
1491
+ }
1492
+ }
1388
1493
}
1389
1494
}
1390
1495
}
1391
1496
1392
- if layout_variants. iter ( ) . all ( |v| v. abi . is_uninhabited ( ) ) {
1393
- abi = Abi :: Uninhabited ;
1394
- }
1395
-
1396
1497
let largest_niche = Niche :: from_scalar ( dl, Size :: ZERO , tag) ;
1397
1498
1398
1499
let layout_variants =
0 commit comments