about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorLukas Markeffsky <@>2023-07-02 14:07:08 +0200
committerLukas Markeffsky <@>2023-07-06 13:15:05 +0000
commite3de14e46396694e48bfecf963fe9fa8e8a90d86 (patch)
treec7e9984848e1e425f398e113c42b92decedaa816 /compiler
parent478071ba9daabcdbc880db5638989dc16545537c (diff)
downloadrust-e3de14e46396694e48bfecf963fe9fa8e8a90d86.tar.gz
rust-e3de14e46396694e48bfecf963fe9fa8e8a90d86.zip
sanity check field offsets in unsizeable structs
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs49
1 files changed, 49 insertions, 0 deletions
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index f6bc0dc330d..0dbe6265522 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -499,6 +499,55 @@ fn layout_of_uncached<'tcx>(
                 return Err(error(cx, LayoutError::SizeOverflow(ty)));
             };
 
+            // If the struct tail is sized and can be unsized, check that unsizing doesn't move the fields around.
+            if cfg!(debug_assertions)
+                && maybe_unsized
+                && def
+                    .non_enum_variant()
+                    .fields
+                    .raw
+                    .last()
+                    .unwrap()
+                    .ty(tcx, substs)
+                    .is_sized(tcx, cx.param_env)
+            {
+                let mut variants = variants;
+                let tail_replacement = cx.layout_of(Ty::new_slice(tcx, tcx.types.u8)).unwrap();
+                *variants[FIRST_VARIANT].raw.last_mut().unwrap() = tail_replacement.layout;
+
+                let Some(unsized_layout) = cx.layout_of_struct_or_enum(
+                    &def.repr(),
+                    &variants,
+                    def.is_enum(),
+                    def.is_unsafe_cell(),
+                    tcx.layout_scalar_valid_range(def.did()),
+                    get_discriminant_type,
+                    discriminants_iter(),
+                    dont_niche_optimize_enum,
+                    !maybe_unsized,
+                ) else {
+                    bug!("failed to compute unsized layout of {ty:?}");
+                };
+
+                let FieldsShape::Arbitrary { offsets: sized_offsets, .. } = &layout.fields else {
+                    bug!("unexpected FieldsShape for sized layout of {ty:?}: {:?}", layout.fields);
+                };
+                let FieldsShape::Arbitrary { offsets: unsized_offsets, .. } = &unsized_layout.fields else {
+                    bug!("unexpected FieldsShape for unsized layout of {ty:?}: {:?}", unsized_layout.fields);
+                };
+
+                let (sized_tail, sized_fields) = sized_offsets.raw.split_last().unwrap();
+                let (unsized_tail, unsized_fields) = unsized_offsets.raw.split_last().unwrap();
+
+                if sized_fields != unsized_fields {
+                    bug!("unsizing {ty:?} changed field order!\n{layout:?}\n{unsized_layout:?}");
+                }
+
+                if sized_tail < unsized_tail {
+                    bug!("unsizing {ty:?} moved tail backwards!\n{layout:?}\n{unsized_layout:?}");
+                }
+            }
+
             tcx.mk_layout(layout)
         }