@@ -2,7 +2,10 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
22use crate :: mir:: { GeneratorLayout , GeneratorSavedLocal } ;
33use crate :: ty:: normalize_erasing_regions:: NormalizationError ;
44use 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+ } ;
69use rustc_ast as ast;
710use rustc_attr as attr;
811use rustc_hir as hir;
@@ -221,295 +224,6 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
221224 }
222225}
223226
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-
513227#[ instrument( skip( tcx, query) , level = "debug" ) ]
514228fn layout_of < ' tcx > (
515229 tcx : TyCtxt < ' tcx > ,
0 commit comments