@@ -221,6 +221,111 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
221
221
}
222
222
}
223
223
224
+ /// Enforce some basic invariants on layouts.
225
+ fn sanity_check_layout < ' tcx > (
226
+ tcx : TyCtxt < ' tcx > ,
227
+ param_env : ty:: ParamEnv < ' tcx > ,
228
+ layout : & TyAndLayout < ' tcx > ,
229
+ ) {
230
+ // Type-level uninhabitedness should always imply ABI uninhabitedness.
231
+ if tcx. conservative_is_privately_uninhabited ( param_env. and ( layout. ty ) ) {
232
+ assert ! ( layout. abi. is_uninhabited( ) ) ;
233
+ }
234
+
235
+ if cfg ! ( debug_assertions) {
236
+ fn check_layout_abi < ' tcx > ( tcx : TyCtxt < ' tcx > , layout : Layout < ' tcx > ) {
237
+ match layout. abi ( ) {
238
+ Abi :: Scalar ( _scalar) => {
239
+ // No padding in scalars.
240
+ /* FIXME(#96185):
241
+ assert_eq!(
242
+ layout.align().abi,
243
+ scalar.align(&tcx).abi,
244
+ "alignment mismatch between ABI and layout in {layout:#?}"
245
+ );
246
+ assert_eq!(
247
+ layout.size(),
248
+ scalar.size(&tcx),
249
+ "size mismatch between ABI and layout in {layout:#?}"
250
+ );*/
251
+ }
252
+ Abi :: Vector { count, element } => {
253
+ // No padding in vectors. Alignment can be strengthened, though.
254
+ assert ! (
255
+ layout. align( ) . abi >= element. align( & tcx) . abi,
256
+ "alignment mismatch between ABI and layout in {layout:#?}"
257
+ ) ;
258
+ let size = element. size ( & tcx) * count;
259
+ assert_eq ! (
260
+ layout. size( ) ,
261
+ size. align_to( tcx. data_layout( ) . vector_align( size) . abi) ,
262
+ "size mismatch between ABI and layout in {layout:#?}"
263
+ ) ;
264
+ }
265
+ Abi :: ScalarPair ( scalar1, scalar2) => {
266
+ // Sanity-check scalar pairs. These are a bit more flexible and support
267
+ // padding, but we can at least ensure both fields actually fit into the layout
268
+ // and the alignment requirement has not been weakened.
269
+ let align1 = scalar1. align ( & tcx) . abi ;
270
+ let align2 = scalar2. align ( & tcx) . abi ;
271
+ assert ! (
272
+ layout. align( ) . abi >= cmp:: max( align1, align2) ,
273
+ "alignment mismatch between ABI and layout in {layout:#?}" ,
274
+ ) ;
275
+ let field2_offset = scalar1. size ( & tcx) . align_to ( align2) ;
276
+ assert ! (
277
+ layout. size( ) >= field2_offset + scalar2. size( & tcx) ,
278
+ "size mismatch between ABI and layout in {layout:#?}"
279
+ ) ;
280
+ }
281
+ Abi :: Uninhabited | Abi :: Aggregate { .. } => { } // Nothing to check.
282
+ }
283
+ }
284
+
285
+ check_layout_abi ( tcx, layout. layout ) ;
286
+
287
+ if let Variants :: Multiple { variants, .. } = & layout. variants {
288
+ for variant in variants {
289
+ check_layout_abi ( tcx, * variant) ;
290
+ // No nested "multiple".
291
+ assert ! ( matches!( variant. variants( ) , Variants :: Single { .. } ) ) ;
292
+ // Skip empty variants.
293
+ if variant. size ( ) == Size :: ZERO
294
+ || variant. fields ( ) . count ( ) == 0
295
+ || variant. abi ( ) . is_uninhabited ( )
296
+ {
297
+ // These are never actually accessed anyway, so we can skip them. (Note that
298
+ // sometimes, variants with fields have size 0, and sometimes, variants without
299
+ // fields have non-0 size.)
300
+ continue ;
301
+ }
302
+ // Variants should have the same or a smaller size as the full thing.
303
+ if variant. size ( ) > layout. size {
304
+ bug ! (
305
+ "Type with size {} bytes has variant with size {} bytes: {layout:#?}" ,
306
+ layout. size. bytes( ) ,
307
+ variant. size( ) . bytes( ) ,
308
+ )
309
+ }
310
+ // The top-level ABI and the ABI of the variants should be coherent.
311
+ let abi_coherent = match ( layout. abi , variant. abi ( ) ) {
312
+ ( Abi :: Scalar ( ..) , Abi :: Scalar ( ..) ) => true ,
313
+ ( Abi :: ScalarPair ( ..) , Abi :: ScalarPair ( ..) ) => true ,
314
+ ( Abi :: Uninhabited , _) => true ,
315
+ ( Abi :: Aggregate { .. } , _) => true ,
316
+ _ => false ,
317
+ } ;
318
+ if !abi_coherent {
319
+ bug ! (
320
+ "Variant ABI is incompatible with top-level ABI:\n variant={:#?}\n Top-level: {layout:#?}" ,
321
+ variant
322
+ ) ;
323
+ }
324
+ }
325
+ }
326
+ }
327
+ }
328
+
224
329
#[ instrument( skip( tcx, query) , level = "debug" ) ]
225
330
fn layout_of < ' tcx > (
226
331
tcx : TyCtxt < ' tcx > ,
@@ -264,10 +369,7 @@ fn layout_of<'tcx>(
264
369
265
370
cx. record_layout_for_printing ( layout) ;
266
371
267
- // Type-level uninhabitedness should always imply ABI uninhabitedness.
268
- if tcx. conservative_is_privately_uninhabited ( param_env. and ( ty) ) {
269
- assert ! ( layout. abi. is_uninhabited( ) ) ;
270
- }
372
+ sanity_check_layout ( tcx, param_env, & layout) ;
271
373
272
374
Ok ( layout)
273
375
} )
@@ -1314,9 +1416,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
1314
1416
} ;
1315
1417
let mut abi = Abi :: Aggregate { sized : true } ;
1316
1418
1317
- // Without latter check aligned enums with custom discriminant values
1318
- // Would result in ICE see the issue #92464 for more info
1319
- if tag. size ( dl) == size || variants. iter ( ) . all ( |layout| layout. is_empty ( ) ) {
1419
+ if layout_variants. iter ( ) . all ( |v| v. abi . is_uninhabited ( ) ) {
1420
+ abi = Abi :: Uninhabited ;
1421
+ } else if tag. size ( dl) == size || variants. iter ( ) . all ( |layout| layout. is_empty ( ) ) {
1422
+ // Without latter check aligned enums with custom discriminant values
1423
+ // Would result in ICE see the issue #92464 for more info
1320
1424
abi = Abi :: Scalar ( tag) ;
1321
1425
} else {
1322
1426
// Try to use a ScalarPair for all tagged enums.
@@ -1390,8 +1494,22 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
1390
1494
}
1391
1495
}
1392
1496
1393
- if layout_variants. iter ( ) . all ( |v| v. abi . is_uninhabited ( ) ) {
1394
- abi = Abi :: Uninhabited ;
1497
+ // If we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the
1498
+ // variants to ensure they are consistent. This is because a downcast is
1499
+ // semantically a NOP, and thus should not affect layout.
1500
+ if matches ! ( abi, Abi :: Scalar ( ..) | Abi :: ScalarPair ( ..) ) {
1501
+ for variant in & mut layout_variants {
1502
+ // We only do this for variants with fields; the others are not accessed anyway.
1503
+ // Also do not overwrite any already existing "clever" ABIs.
1504
+ if variant. fields . count ( ) > 0
1505
+ && matches ! ( variant. abi, Abi :: Aggregate { .. } )
1506
+ {
1507
+ variant. abi = abi;
1508
+ // Also need to bump up the size and alignment, so that the entire value fits in here.
1509
+ variant. size = cmp:: max ( variant. size , size) ;
1510
+ variant. align . abi = cmp:: max ( variant. align . abi , align. abi ) ;
1511
+ }
1512
+ }
1395
1513
}
1396
1514
1397
1515
let largest_niche = Niche :: from_scalar ( dl, Size :: ZERO , tag) ;
0 commit comments