about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_abi/src/lib.rs23
-rw-r--r--compiler/rustc_ty_utils/src/layout_sanity_check.rs94
-rw-r--r--compiler/rustc_ty_utils/src/lib.rs1
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<C: HasDataLayout>(&self, cx: &C) -> Option<AbiAndPrefAlign> {
         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<C: HasDataLayout>(&self, cx: &C) -> Option<Size> {
+        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)]