@@ -220,6 +220,91 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
220220 }
221221}
222222
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+
223308#[ instrument( skip( tcx, query) , level = "debug" ) ]
224309fn layout_of < ' tcx > (
225310 tcx : TyCtxt < ' tcx > ,
@@ -263,10 +348,7 @@ fn layout_of<'tcx>(
263348
264349 cx. record_layout_for_printing ( layout) ;
265350
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) ;
270352
271353 Ok ( layout)
272354 } )
@@ -1313,10 +1395,22 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
13131395 } ;
13141396 let mut abi = Abi :: Aggregate { sized : true } ;
13151397
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
13191403 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+ }
13201414 } else {
13211415 // Try to use a ScalarPair for all tagged enums.
13221416 let mut common_prim = None ;
@@ -1385,14 +1479,21 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
13851479 // We can use `ScalarPair` only when it matches our
13861480 // already computed layout (including `#[repr(C)]`).
13871481 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+ }
13881493 }
13891494 }
13901495 }
13911496
1392- if layout_variants. iter ( ) . all ( |v| v. abi . is_uninhabited ( ) ) {
1393- abi = Abi :: Uninhabited ;
1394- }
1395-
13961497 let largest_niche = Niche :: from_scalar ( dl, Size :: ZERO , tag) ;
13971498
13981499 let layout_variants =
0 commit comments