@@ -221,6 +221,111 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
221221 }
222222}
223223
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+
224329#[ instrument( skip( tcx, query) , level = "debug" ) ]
225330fn layout_of < ' tcx > (
226331 tcx : TyCtxt < ' tcx > ,
@@ -264,10 +369,7 @@ fn layout_of<'tcx>(
264369
265370 cx. record_layout_for_printing ( layout) ;
266371
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) ;
271373
272374 Ok ( layout)
273375 } )
@@ -1314,9 +1416,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
13141416 } ;
13151417 let mut abi = Abi :: Aggregate { sized : true } ;
13161418
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
13201424 abi = Abi :: Scalar ( tag) ;
13211425 } else {
13221426 // Try to use a ScalarPair for all tagged enums.
@@ -1390,8 +1494,22 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
13901494 }
13911495 }
13921496
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+ }
13951513 }
13961514
13971515 let largest_niche = Niche :: from_scalar ( dl, Size :: ZERO , tag) ;
0 commit comments