about summary refs log tree commit diff
path: root/compiler/rustc_middle/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-07-07 15:42:29 +0000
committerbors <bors@rust-lang.org>2023-07-07 15:42:29 +0000
commitcb80ff132a0e9aa71529b701427e4e6c243b58df (patch)
tree5e92cefe9b90e442586342ca94732f18d133b9e0 /compiler/rustc_middle/src
parentfd68a6ded951bd7b852ab8107007f7145e3ad6ec (diff)
parent7aa5f39d3b55eb746d9d64244ed5343874807ac4 (diff)
downloadrust-cb80ff132a0e9aa71529b701427e4e6c243b58df.tar.gz
rust-cb80ff132a0e9aa71529b701427e4e6c243b58df.zip
Auto merge of #113245 - lukas-code:unsizing-sanity-check, r=the8472
sanity check field offsets in unsizeable structs

As promised in https://github.com/rust-lang/rust/pull/112062#issuecomment-1567494994, this PR extends the layout sanity checks to ensure that structs fields don't move around when unsizing and prevent issues like https://github.com/rust-lang/rust/issues/112048 in the future. Like most other layout sanity checks, this only runs on compilers with debug assertions enabled.

Here is how it looks when it fails:
```text
error: internal compiler error: compiler/rustc_ty_utils/src/layout.rs:533:21: unsizing GcNode<std::boxed::Box<i32>> changed field order!
                                Layout { size: Size(32 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, abi: Aggregate { sized: true }, fields: Arbitrary { offsets: [Size(0 bytes), Size(8 bytes), Size(24 bytes)], memory_index: [0, 1, 2] }, largest_niche: Some(Niche { offset: Size(24 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), variants: Single { index: 0 } }
                                Layout { size: Size(24 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, abi: Aggregate { sized: false }, fields: Arbitrary { offsets: [Size(16 bytes), Size(0 bytes), Size(24 bytes)], memory_index: [1, 0, 2] }, largest_niche: None, variants: Single { index: 0 } }
```

r? `@the8472`
Diffstat (limited to 'compiler/rustc_middle/src')
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs16
-rw-r--r--compiler/rustc_middle/src/ty/util.rs4
2 files changed, 18 insertions, 2 deletions
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 938b901c2f7..aa8bfd3178c 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2035,6 +2035,22 @@ impl VariantDef {
 
         &self.fields[FieldIdx::from_u32(0)]
     }
+
+    /// Returns the last field in this variant, if present.
+    #[inline]
+    pub fn tail_opt(&self) -> Option<&FieldDef> {
+        self.fields.raw.last()
+    }
+
+    /// Returns the last field in this variant.
+    ///
+    /// # Panics
+    ///
+    /// Panics, if the variant has no fields.
+    #[inline]
+    pub fn tail(&self) -> &FieldDef {
+        self.tail_opt().expect("expected unsized ADT to have a tail field")
+    }
 }
 
 impl PartialEq for VariantDef {
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 720d770eed4..e2e4a2dbdc8 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -230,7 +230,7 @@ impl<'tcx> TyCtxt<'tcx> {
                     if !def.is_struct() {
                         break;
                     }
-                    match def.non_enum_variant().fields.raw.last() {
+                    match def.non_enum_variant().tail_opt() {
                         Some(field) => {
                             f();
                             ty = field.ty(self, substs);
@@ -304,7 +304,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 (&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs))
                     if a_def == b_def && a_def.is_struct() =>
                 {
-                    if let Some(f) = a_def.non_enum_variant().fields.raw.last() {
+                    if let Some(f) = a_def.non_enum_variant().tail_opt() {
                         a = f.ty(self, a_substs);
                         b = f.ty(self, b_substs);
                     } else {