@@ -240,7 +240,11 @@ fn sanity_check_layout<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: &TyAndLa
240240 ) -> impl Iterator < Item = ( Size , TyAndLayout < ' tcx > ) > + ' a {
241241 ( 0 ..layout. layout . fields ( ) . count ( ) ) . filter_map ( |i| {
242242 let field = layout. field ( cx, i) ;
243- let zst = field. is_zst ( ) && field. align . abi . bytes ( ) == 1 ;
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 ( ) ;
244248 ( !zst) . then ( || ( layout. fields . offset ( i) , field) )
245249 } )
246250 }
@@ -327,38 +331,120 @@ fn sanity_check_layout<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: &TyAndLa
327331 field. align. abi, align,
328332 "`Scalar` field with bad align in {inner:#?}" ,
329333 ) ;
334+ assert ! (
335+ matches!( field. abi, Abi :: Scalar ( _) ) ,
336+ "`Scalar` field with bad ABI in {inner:#?}" ,
337+ ) ;
330338 }
331339 _ => {
332340 panic ! ( "`Scalar` layout for non-primitive non-enum type {}" , inner. ty) ;
333341 }
334342 }
335343 }
336- Abi :: Vector { count, element } => {
337- // No padding in vectors. Alignment can be strengthened, though.
338- assert ! (
339- layout. layout. align( ) . abi >= element. align( cx) . abi,
340- "alignment mismatch between ABI and layout in {layout:#?}"
341- ) ;
342- let size = element. size ( cx) * count;
343- assert_eq ! (
344- layout. layout. size( ) ,
345- size. align_to( cx. data_layout( ) . vector_align( size) . abi) ,
346- "size mismatch between ABI and layout in {layout:#?}"
347- ) ;
348- }
349344 Abi :: ScalarPair ( scalar1, scalar2) => {
350345 // Sanity-check scalar pairs. These are a bit more flexible and support
351346 // padding, but we can at least ensure both fields actually fit into the layout
352347 // and the alignment requirement has not been weakened.
348+ let size1 = scalar1. size ( cx) ;
353349 let align1 = scalar1. align ( cx) . abi ;
350+ let size2 = scalar2. size ( cx) ;
354351 let align2 = scalar2. align ( cx) . abi ;
355352 assert ! (
356353 layout. layout. align( ) . abi >= cmp:: max( align1, align2) ,
357354 "alignment mismatch between ABI and layout in {layout:#?}" ,
358355 ) ;
359- let field2_offset = scalar1. size ( cx) . align_to ( align2) ;
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.
360440 assert ! (
361- layout. layout. size( ) >= field2_offset + scalar2. size( cx) ,
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) ,
362448 "size mismatch between ABI and layout in {layout:#?}"
363449 ) ;
364450 }
0 commit comments