From 3b1e535f36ac4c47dc91d0e3394dca72fb86db0c Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sat, 18 Feb 2023 19:21:07 -0800 Subject: [PATCH] Factor out checks in layout check and add helper inherent_size. --- compiler/rustc_abi/src/lib.rs | 23 ++++- .../rustc_ty_utils/src/layout_sanity_check.rs | 94 ++++++++----------- compiler/rustc_ty_utils/src/lib.rs | 1 + 3 files changed, 63 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index bbbc417e892..9c8a59979aa 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1273,7 +1273,7 @@ impl Abi { matches!(*self, Abi::Scalar(_)) } - /// Returns the fixed alignment of this ABI, if any + /// Returns the fixed alignment of this ABI, if any is mandated. pub fn inherent_align(&self, cx: &C) -> Option { Some(match *self { Abi::Scalar(s) => s.align(cx), @@ -1287,6 +1287,27 @@ impl Abi { }) } + /// Returns the fixed size of this ABI, if any is mandated. + pub fn inherent_size(&self, cx: &C) -> Option { + Some(match *self { + Abi::Scalar(s) => { + // No padding in scalars. + s.size(cx) + } + Abi::ScalarPair(s1, s2) => { + // May have some padding between the pair. + let field2_offset = s1.size(cx).align_to(s2.align(cx).abi); + (field2_offset + s2.size(cx)).align_to(self.inherent_align(cx)?.abi) + } + Abi::Vector { element, count } => { + // No padding in vectors, except possibly for trailing padding + // to make the size a multiple of align (e.g. for vectors of size 3). + (element.size(cx) * count).align_to(self.inherent_align(cx)?.abi) + } + Abi::Uninhabited | Abi::Aggregate { .. } => return None, + }) + } + /// Discard valid range information and allow undef pub fn to_union(&self) -> Self { assert!(self.is_sized()); diff --git a/compiler/rustc_ty_utils/src/layout_sanity_check.rs b/compiler/rustc_ty_utils/src/layout_sanity_check.rs index ed513cb3c7f..c4a4cda6801 100644 --- a/compiler/rustc_ty_utils/src/layout_sanity_check.rs +++ b/compiler/rustc_ty_utils/src/layout_sanity_check.rs @@ -4,7 +4,7 @@ use rustc_middle::ty::{ }; use rustc_target::abi::*; -use std::cmp; +use std::assert_matches::assert_matches; /// Enforce some basic invariants on layouts. pub(super) fn sanity_check_layout<'tcx>( @@ -68,21 +68,31 @@ pub(super) fn sanity_check_layout<'tcx>( } fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: &TyAndLayout<'tcx>) { + // Verify the ABI mandated alignment and size. + let align = layout.abi.inherent_align(cx).map(|align| align.abi); + let size = layout.abi.inherent_size(cx); + let Some((align, size)) = align.zip(size) else { + assert_matches!( + layout.layout.abi(), + Abi::Uninhabited | Abi::Aggregate { .. }, + "ABI unexpectedly missing alignment and/or size in {layout:#?}" + ); + return + }; + assert_eq!( + layout.layout.align().abi, + align, + "alignment mismatch between ABI and layout in {layout:#?}" + ); + assert_eq!( + layout.layout.size(), + size, + "size mismatch between ABI and layout in {layout:#?}" + ); + + // Verify per-ABI invariants match layout.layout.abi() { - Abi::Scalar(scalar) => { - // No padding in scalars. - let size = scalar.size(cx); - let align = scalar.align(cx).abi; - assert_eq!( - layout.layout.size(), - size, - "size mismatch between ABI and layout in {layout:#?}" - ); - assert_eq!( - layout.layout.align().abi, - align, - "alignment mismatch between ABI and layout in {layout:#?}" - ); + Abi::Scalar(_) => { // Check that this matches the underlying field. let inner = skip_newtypes(cx, layout); assert!( @@ -135,24 +145,6 @@ pub(super) fn sanity_check_layout<'tcx>( } } Abi::ScalarPair(scalar1, scalar2) => { - // Sanity-check scalar pairs. Computing the expected size and alignment is a bit of work. - let size1 = scalar1.size(cx); - let align1 = scalar1.align(cx).abi; - let size2 = scalar2.size(cx); - let align2 = scalar2.align(cx).abi; - let align = cmp::max(align1, align2); - let field2_offset = size1.align_to(align2); - let size = (field2_offset + size2).align_to(align); - assert_eq!( - layout.layout.size(), - size, - "size mismatch between ABI and layout in {layout:#?}" - ); - assert_eq!( - layout.layout.align().abi, - align, - "alignment mismatch between ABI and layout in {layout:#?}", - ); // Check that the underlying pair of fields matches. let inner = skip_newtypes(cx, layout); assert!( @@ -189,8 +181,9 @@ pub(super) fn sanity_check_layout<'tcx>( "`ScalarPair` layout for type with less than two non-ZST fields: {inner:#?}" ) }); - assert!( - fields.next().is_none(), + assert_matches!( + fields.next(), + None, "`ScalarPair` layout for type with at least three non-ZST fields: {inner:#?}" ); // The fields might be in opposite order. @@ -200,6 +193,10 @@ pub(super) fn sanity_check_layout<'tcx>( (offset2, field2, offset1, field1) }; // The fields should be at the right offset, and match the `scalar` layout. + let size1 = scalar1.size(cx); + let align1 = scalar1.align(cx).abi; + let size2 = scalar2.size(cx); + let align2 = scalar2.align(cx).abi; assert_eq!( offset1, Size::ZERO, @@ -213,10 +210,12 @@ pub(super) fn sanity_check_layout<'tcx>( field1.align.abi, align1, "`ScalarPair` first field with bad align in {inner:#?}", ); - assert!( - matches!(field1.abi, Abi::Scalar(_)), + assert_matches!( + field1.abi, + Abi::Scalar(_), "`ScalarPair` first field with bad ABI in {inner:#?}", ); + let field2_offset = size1.align_to(align2); assert_eq!( offset2, field2_offset, "`ScalarPair` second field at bad offset in {inner:#?}", @@ -229,27 +228,14 @@ pub(super) fn sanity_check_layout<'tcx>( field2.align.abi, align2, "`ScalarPair` second field with bad align in {inner:#?}", ); - assert!( - matches!(field2.abi, Abi::Scalar(_)), + assert_matches!( + field2.abi, + Abi::Scalar(_), "`ScalarPair` second field with bad ABI in {inner:#?}", ); } - Abi::Vector { count, element } => { - // No padding in vectors, except possibly for trailing padding to make the size a multiple of align. - let size = element.size(cx) * count; - let align = cx.data_layout().vector_align(size).abi; - let size = size.align_to(align); // needed e.g. for vectors of size 3 + Abi::Vector { element, .. } => { assert!(align >= element.align(cx).abi); // just sanity-checking `vector_align`. - assert_eq!( - layout.layout.size(), - size, - "size mismatch between ABI and layout in {layout:#?}" - ); - assert_eq!( - layout.layout.align().abi, - align, - "alignment mismatch between ABI and layout in {layout:#?}" - ); // FIXME: Do some kind of check of the inner type, like for Scalar and ScalarPair. } Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check. diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 9d5a72a73cd..73a2f6af579 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -5,6 +5,7 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(assert_matches)] #![feature(iterator_try_collect)] #![feature(let_chains)] #![feature(never_type)]