about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMoulins <arthur.heuillard@orange.fr>2023-07-01 23:32:14 +0200
committerMoulins <arthur.heuillard@orange.fr>2023-07-21 03:31:46 +0200
commitbf2f8ff2ec5c0b54480d4908ff888a5e650d7dc5 (patch)
tree2924b333b51000516f43772eb9aef753af80715a
parent8e28729a8200e8bc3f625418a724123029c4e215 (diff)
downloadrust-bf2f8ff2ec5c0b54480d4908ff888a5e650d7dc5.tar.gz
rust-bf2f8ff2ec5c0b54480d4908ff888a5e650d7dc5.zip
Move `naive_layout_of` query provider in separate sibling module
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs234
-rw-r--r--compiler/rustc_ty_utils/src/layout_naive.rs240
-rw-r--r--compiler/rustc_ty_utils/src/layout_sanity_check.rs7
-rw-r--r--compiler/rustc_ty_utils/src/lib.rs2
4 files changed, 253 insertions, 230 deletions
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 8c484e95491..da1eba68d53 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -5,8 +5,7 @@ use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::mir::{GeneratorLayout, GeneratorSavedLocal};
 use rustc_middle::query::{LocalCrate, Providers};
 use rustc_middle::ty::layout::{
-    IntegerExt, LayoutCx, LayoutError, LayoutOf, NaiveAbi, NaiveLayout, TyAndLayout,
-    TyAndNaiveLayout, MAX_SIMD_LANES,
+    IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
 };
 use rustc_middle::ty::{
     self, AdtDef, EarlyBinder, GenericArgsRef, ReprOptions, Ty, TyCtxt, TypeVisitableExt,
@@ -25,7 +24,7 @@ use crate::errors::{
 use crate::layout_sanity_check::sanity_check_layout;
 
 pub fn provide(providers: &mut Providers) {
-    *providers = Providers { layout_of, naive_layout_of, reference_niches_policy, ..*providers };
+    *providers = Providers { layout_of, reference_niches_policy, ..*providers };
 }
 
 #[instrument(skip(tcx), level = "debug")]
@@ -38,40 +37,6 @@ fn reference_niches_policy<'tcx>(tcx: TyCtxt<'tcx>, _: LocalCrate) -> ReferenceN
 const DEFAULT_REF_NICHES: ReferenceNichePolicy = ReferenceNichePolicy { size: false, align: false };
 
 #[instrument(skip(tcx, query), level = "debug")]
-fn naive_layout_of<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
-) -> Result<TyAndNaiveLayout<'tcx>, &'tcx LayoutError<'tcx>> {
-    let (param_env, ty) = query.into_parts();
-    debug!(?ty);
-
-    let param_env = param_env.with_reveal_all_normalized(tcx);
-    let unnormalized_ty = ty;
-
-    // FIXME: We might want to have two different versions of `layout_of`:
-    // One that can be called after typecheck has completed and can use
-    // `normalize_erasing_regions` here and another one that can be called
-    // before typecheck has completed and uses `try_normalize_erasing_regions`.
-    let ty = match tcx.try_normalize_erasing_regions(param_env, ty) {
-        Ok(t) => t,
-        Err(normalization_error) => {
-            return Err(tcx
-                .arena
-                .alloc(LayoutError::NormalizationFailure(ty, normalization_error)));
-        }
-    };
-
-    if ty != unnormalized_ty {
-        // Ensure this layout is also cached for the normalized type.
-        return tcx.naive_layout_of(param_env.and(ty));
-    }
-
-    let cx = LayoutCx { tcx, param_env };
-    let layout = naive_layout_of_uncached(&cx, ty)?;
-    Ok(TyAndNaiveLayout { ty, layout })
-}
-
-#[instrument(skip(tcx, query), level = "debug")]
 fn layout_of<'tcx>(
     tcx: TyCtxt<'tcx>,
     query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
@@ -90,13 +55,9 @@ fn layout_of<'tcx>(
     let cx = LayoutCx { tcx, param_env };
     let layout = layout_of_uncached(&cx, ty)?;
 
-    if !naive.is_refined_by(layout) {
-        bug!("the naive layout isn't refined by the actual layout:\n{:#?}\n{:#?}", naive, layout,);
-    }
-
     let layout = TyAndLayout { ty, layout };
     record_layout_for_printing(&cx, layout);
-    sanity_check_layout(&cx, &layout);
+    sanity_check_layout(&cx, &layout, &naive);
 
     Ok(layout)
 }
@@ -108,191 +69,6 @@ fn error<'tcx>(
     cx.tcx.arena.alloc(err)
 }
 
-fn naive_layout_of_uncached<'tcx>(
-    cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
-    ty: Ty<'tcx>,
-) -> Result<NaiveLayout, &'tcx LayoutError<'tcx>> {
-    let tcx = cx.tcx;
-    let dl = cx.data_layout();
-
-    let scalar = |value: Primitive| NaiveLayout {
-        abi: NaiveAbi::Scalar(value),
-        size: value.size(dl),
-        align: value.align(dl).abi,
-        exact: true,
-    };
-
-    let univariant = |fields: &mut dyn Iterator<Item = Ty<'tcx>>,
-                      repr: &ReprOptions|
-     -> Result<NaiveLayout, &'tcx LayoutError<'tcx>> {
-        if repr.pack.is_some() && repr.align.is_some() {
-            cx.tcx.sess.delay_span_bug(DUMMY_SP, "struct cannot be packed and aligned");
-            return Err(error(cx, LayoutError::Unknown(ty)));
-        }
-
-        let linear = repr.inhibit_struct_field_reordering_opt();
-        let pack = repr.pack.unwrap_or(Align::MAX);
-        let mut layout = NaiveLayout::EMPTY;
-
-        for field in fields {
-            let field = cx.naive_layout_of(field)?.packed(pack);
-            if linear {
-                layout = layout.pad_to_align(field.align);
-            }
-            layout = layout
-                .concat(&field, dl)
-                .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?;
-        }
-
-        if let Some(align) = repr.align {
-            layout = layout.align_to(align);
-        }
-
-        if linear {
-            layout.abi = layout.abi.as_aggregate();
-        }
-
-        Ok(layout.pad_to_align(layout.align))
-    };
-
-    debug_assert!(!ty.has_non_region_infer());
-
-    Ok(match *ty.kind() {
-        // Basic scalars
-        ty::Bool => scalar(Int(I8, false)),
-        ty::Char => scalar(Int(I32, false)),
-        ty::Int(ity) => scalar(Int(Integer::from_int_ty(dl, ity), true)),
-        ty::Uint(ity) => scalar(Int(Integer::from_uint_ty(dl, ity), false)),
-        ty::Float(fty) => scalar(match fty {
-            ty::FloatTy::F32 => F32,
-            ty::FloatTy::F64 => F64,
-        }),
-        ty::FnPtr(_) => scalar(Pointer(dl.instruction_address_space)),
-
-        // The never type.
-        ty::Never => NaiveLayout { abi: NaiveAbi::Uninhabited, ..NaiveLayout::EMPTY },
-
-        // Potentially-wide pointers.
-        ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
-            let data_ptr = scalar(Pointer(AddressSpace::DATA));
-            if let Some(metadata) = ptr_metadata_scalar(cx, pointee)? {
-                // Effectively a (ptr, meta) tuple.
-                let l = data_ptr
-                    .concat(&scalar(metadata.primitive()), dl)
-                    .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?;
-                l.pad_to_align(l.align)
-            } else {
-                // No metadata, this is a thin pointer.
-                data_ptr
-            }
-        }
-
-        ty::Dynamic(_, _, ty::DynStar) => {
-            let ptr = scalar(Pointer(AddressSpace::DATA));
-            ptr.concat(&ptr, dl).ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?
-        }
-
-        // Arrays and slices.
-        ty::Array(element, count) => {
-            let count = compute_array_count(cx, count)
-                .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
-            let element = cx.naive_layout_of(element)?;
-            NaiveLayout {
-                abi: element.abi.as_aggregate(),
-                size: element
-                    .size
-                    .checked_mul(count, cx)
-                    .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?,
-                ..*element
-            }
-        }
-        ty::Slice(element) => {
-            let element = cx.naive_layout_of(element)?;
-            NaiveLayout { abi: NaiveAbi::Unsized, size: Size::ZERO, ..*element }
-        }
-
-        ty::FnDef(..) => NaiveLayout::EMPTY,
-
-        // Unsized types.
-        ty::Str | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => {
-            NaiveLayout { abi: NaiveAbi::Unsized, ..NaiveLayout::EMPTY }
-        }
-
-        // FIXME(reference_niches): try to actually compute a reasonable layout estimate,
-        // without duplicating too much code from `generator_layout`.
-        ty::Generator(..) => NaiveLayout { exact: false, ..NaiveLayout::EMPTY },
-
-        ty::Closure(_, ref substs) => {
-            univariant(&mut substs.as_closure().upvar_tys(), &ReprOptions::default())?
-        }
-
-        ty::Tuple(tys) => univariant(&mut tys.iter(), &ReprOptions::default())?,
-
-        ty::Adt(def, substs) if def.is_union() => {
-            let repr = def.repr();
-            let pack = repr.pack.unwrap_or(Align::MAX);
-            if repr.pack.is_some() && repr.align.is_some() {
-                cx.tcx.sess.delay_span_bug(DUMMY_SP, "union cannot be packed and aligned");
-                return Err(error(cx, LayoutError::Unknown(ty)));
-            }
-
-            let mut layout = NaiveLayout::EMPTY;
-            for f in &def.variants()[FIRST_VARIANT].fields {
-                let field = cx.naive_layout_of(f.ty(tcx, substs))?;
-                layout = layout.union(&field.packed(pack));
-            }
-
-            // Unions are always inhabited, and never scalar if `repr(C)`.
-            if !matches!(layout.abi, NaiveAbi::Scalar(_)) || repr.inhibit_enum_layout_opt() {
-                layout.abi = NaiveAbi::Sized;
-            }
-
-            if let Some(align) = repr.align {
-                layout = layout.align_to(align);
-            }
-            layout.pad_to_align(layout.align)
-        }
-
-        ty::Adt(def, substs) => {
-            let repr = def.repr();
-            let base = NaiveLayout {
-                // For simplicity, assume that any enum has its discriminant field (if it exists)
-                // niched inside one of the variants; this will underestimate the size (and sometimes
-                // alignment) of enums. We also doesn't compute exact alignment for SIMD structs.
-                // FIXME(reference_niches): Be smarter here.
-                // Also consider adding a special case for null-optimized enums, so that we can have
-                // `Option<&T>: PointerLike` in generic contexts.
-                exact: !def.is_enum() && !repr.simd(),
-                // An ADT with no inhabited variants should have an uninhabited ABI.
-                abi: NaiveAbi::Uninhabited,
-                ..NaiveLayout::EMPTY
-            };
-
-            let layout = def.variants().iter().try_fold(base, |layout, v| {
-                let mut fields = v.fields.iter().map(|f| f.ty(tcx, substs));
-                let vlayout = univariant(&mut fields, &repr)?;
-                Ok(layout.union(&vlayout))
-            })?;
-            layout.pad_to_align(layout.align)
-        }
-
-        // Types with no meaningful known layout.
-        ty::Alias(..) => {
-            // NOTE(eddyb) `layout_of` query should've normalized these away,
-            // if that was possible, so there's no reason to try again here.
-            return Err(error(cx, LayoutError::Unknown(ty)));
-        }
-
-        ty::Bound(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) | ty::Infer(_) => {
-            bug!("Layout::compute: unexpected type `{}`", ty)
-        }
-
-        ty::Placeholder(..) | ty::Param(_) | ty::Error(_) => {
-            return Err(error(cx, LayoutError::Unknown(ty)));
-        }
-    })
-}
-
 fn univariant_uninterned<'tcx>(
     cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
     ty: Ty<'tcx>,
@@ -739,7 +515,7 @@ fn layout_of_uncached<'tcx>(
     })
 }
 
-fn compute_array_count<'tcx>(
+pub(crate) fn compute_array_count<'tcx>(
     cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
     mut count: ty::Const<'tcx>,
 ) -> Option<u64> {
@@ -754,7 +530,7 @@ fn compute_array_count<'tcx>(
     count.try_eval_target_usize(tcx, param_env)
 }
 
-fn ptr_metadata_scalar<'tcx>(
+pub(crate) fn ptr_metadata_scalar<'tcx>(
     cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
     pointee: Ty<'tcx>,
 ) -> Result<Option<Scalar>, &'tcx LayoutError<'tcx>> {
diff --git a/compiler/rustc_ty_utils/src/layout_naive.rs b/compiler/rustc_ty_utils/src/layout_naive.rs
new file mode 100644
index 00000000000..501b27777fa
--- /dev/null
+++ b/compiler/rustc_ty_utils/src/layout_naive.rs
@@ -0,0 +1,240 @@
+use rustc_middle::query::Providers;
+use rustc_middle::ty::layout::{
+    IntegerExt, LayoutCx, LayoutError, LayoutOf, NaiveAbi, NaiveLayout, TyAndNaiveLayout,
+};
+use rustc_middle::ty::{self, ReprOptions, Ty, TyCtxt, TypeVisitableExt};
+
+use rustc_span::DUMMY_SP;
+use rustc_target::abi::*;
+
+use crate::layout::{compute_array_count, ptr_metadata_scalar};
+
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers { naive_layout_of, ..*providers };
+}
+
+#[instrument(skip(tcx, query), level = "debug")]
+fn naive_layout_of<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+) -> Result<TyAndNaiveLayout<'tcx>, &'tcx LayoutError<'tcx>> {
+    let (param_env, ty) = query.into_parts();
+    debug!(?ty);
+
+    let param_env = param_env.with_reveal_all_normalized(tcx);
+    let unnormalized_ty = ty;
+
+    // FIXME: We might want to have two different versions of `layout_of`:
+    // One that can be called after typecheck has completed and can use
+    // `normalize_erasing_regions` here and another one that can be called
+    // before typecheck has completed and uses `try_normalize_erasing_regions`.
+    let ty = match tcx.try_normalize_erasing_regions(param_env, ty) {
+        Ok(t) => t,
+        Err(normalization_error) => {
+            return Err(tcx
+                .arena
+                .alloc(LayoutError::NormalizationFailure(ty, normalization_error)));
+        }
+    };
+
+    if ty != unnormalized_ty {
+        // Ensure this layout is also cached for the normalized type.
+        return tcx.naive_layout_of(param_env.and(ty));
+    }
+
+    let cx = LayoutCx { tcx, param_env };
+    let layout = naive_layout_of_uncached(&cx, ty)?;
+    Ok(TyAndNaiveLayout { ty, layout })
+}
+
+fn error<'tcx>(
+    cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
+    err: LayoutError<'tcx>,
+) -> &'tcx LayoutError<'tcx> {
+    cx.tcx.arena.alloc(err)
+}
+
+fn naive_layout_of_uncached<'tcx>(
+    cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
+    ty: Ty<'tcx>,
+) -> Result<NaiveLayout, &'tcx LayoutError<'tcx>> {
+    let tcx = cx.tcx;
+    let dl = cx.data_layout();
+
+    let scalar = |value: Primitive| NaiveLayout {
+        abi: NaiveAbi::Scalar(value),
+        size: value.size(dl),
+        align: value.align(dl).abi,
+        exact: true,
+    };
+
+    let univariant = |fields: &mut dyn Iterator<Item = Ty<'tcx>>,
+                      repr: &ReprOptions|
+     -> Result<NaiveLayout, &'tcx LayoutError<'tcx>> {
+        if repr.pack.is_some() && repr.align.is_some() {
+            cx.tcx.sess.delay_span_bug(DUMMY_SP, "struct cannot be packed and aligned");
+            return Err(error(cx, LayoutError::Unknown(ty)));
+        }
+
+        let linear = repr.inhibit_struct_field_reordering_opt();
+        let pack = repr.pack.unwrap_or(Align::MAX);
+        let mut layout = NaiveLayout::EMPTY;
+
+        for field in fields {
+            let field = cx.naive_layout_of(field)?.packed(pack);
+            if linear {
+                layout = layout.pad_to_align(field.align);
+            }
+            layout = layout
+                .concat(&field, dl)
+                .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?;
+        }
+
+        if let Some(align) = repr.align {
+            layout = layout.align_to(align);
+        }
+
+        if linear {
+            layout.abi = layout.abi.as_aggregate();
+        }
+
+        Ok(layout.pad_to_align(layout.align))
+    };
+
+    debug_assert!(!ty.has_non_region_infer());
+
+    Ok(match *ty.kind() {
+        // Basic scalars
+        ty::Bool => scalar(Int(I8, false)),
+        ty::Char => scalar(Int(I32, false)),
+        ty::Int(ity) => scalar(Int(Integer::from_int_ty(dl, ity), true)),
+        ty::Uint(ity) => scalar(Int(Integer::from_uint_ty(dl, ity), false)),
+        ty::Float(fty) => scalar(match fty {
+            ty::FloatTy::F32 => F32,
+            ty::FloatTy::F64 => F64,
+        }),
+        ty::FnPtr(_) => scalar(Pointer(dl.instruction_address_space)),
+
+        // The never type.
+        ty::Never => NaiveLayout { abi: NaiveAbi::Uninhabited, ..NaiveLayout::EMPTY },
+
+        // Potentially-wide pointers.
+        ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
+            let data_ptr = scalar(Pointer(AddressSpace::DATA));
+            if let Some(metadata) = ptr_metadata_scalar(cx, pointee)? {
+                // Effectively a (ptr, meta) tuple.
+                let l = data_ptr
+                    .concat(&scalar(metadata.primitive()), dl)
+                    .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?;
+                l.pad_to_align(l.align)
+            } else {
+                // No metadata, this is a thin pointer.
+                data_ptr
+            }
+        }
+
+        ty::Dynamic(_, _, ty::DynStar) => {
+            let ptr = scalar(Pointer(AddressSpace::DATA));
+            ptr.concat(&ptr, dl).ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?
+        }
+
+        // Arrays and slices.
+        ty::Array(element, count) => {
+            let count = compute_array_count(cx, count)
+                .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
+            let element = cx.naive_layout_of(element)?;
+            NaiveLayout {
+                abi: element.abi.as_aggregate(),
+                size: element
+                    .size
+                    .checked_mul(count, cx)
+                    .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?,
+                ..*element
+            }
+        }
+        ty::Slice(element) => {
+            let element = cx.naive_layout_of(element)?;
+            NaiveLayout { abi: NaiveAbi::Unsized, size: Size::ZERO, ..*element }
+        }
+
+        ty::FnDef(..) => NaiveLayout::EMPTY,
+
+        // Unsized types.
+        ty::Str | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => {
+            NaiveLayout { abi: NaiveAbi::Unsized, ..NaiveLayout::EMPTY }
+        }
+
+        // FIXME(reference_niches): try to actually compute a reasonable layout estimate,
+        // without duplicating too much code from `generator_layout`.
+        ty::Generator(..) => NaiveLayout { exact: false, ..NaiveLayout::EMPTY },
+
+        ty::Closure(_, ref substs) => {
+            univariant(&mut substs.as_closure().upvar_tys(), &ReprOptions::default())?
+        }
+
+        ty::Tuple(tys) => univariant(&mut tys.iter(), &ReprOptions::default())?,
+
+        ty::Adt(def, substs) if def.is_union() => {
+            let repr = def.repr();
+            let pack = repr.pack.unwrap_or(Align::MAX);
+            if repr.pack.is_some() && repr.align.is_some() {
+                cx.tcx.sess.delay_span_bug(DUMMY_SP, "union cannot be packed and aligned");
+                return Err(error(cx, LayoutError::Unknown(ty)));
+            }
+
+            let mut layout = NaiveLayout::EMPTY;
+            for f in &def.variants()[FIRST_VARIANT].fields {
+                let field = cx.naive_layout_of(f.ty(tcx, substs))?;
+                layout = layout.union(&field.packed(pack));
+            }
+
+            // Unions are always inhabited, and never scalar if `repr(C)`.
+            if !matches!(layout.abi, NaiveAbi::Scalar(_)) || repr.inhibit_enum_layout_opt() {
+                layout.abi = NaiveAbi::Sized;
+            }
+
+            if let Some(align) = repr.align {
+                layout = layout.align_to(align);
+            }
+            layout.pad_to_align(layout.align)
+        }
+
+        ty::Adt(def, substs) => {
+            let repr = def.repr();
+            let base = NaiveLayout {
+                // For simplicity, assume that any enum has its discriminant field (if it exists)
+                // niched inside one of the variants; this will underestimate the size (and sometimes
+                // alignment) of enums. We also doesn't compute exact alignment for SIMD structs.
+                // FIXME(reference_niches): Be smarter here.
+                // Also consider adding a special case for null-optimized enums, so that we can have
+                // `Option<&T>: PointerLike` in generic contexts.
+                exact: !def.is_enum() && !repr.simd(),
+                // An ADT with no inhabited variants should have an uninhabited ABI.
+                abi: NaiveAbi::Uninhabited,
+                ..NaiveLayout::EMPTY
+            };
+
+            let layout = def.variants().iter().try_fold(base, |layout, v| {
+                let mut fields = v.fields.iter().map(|f| f.ty(tcx, substs));
+                let vlayout = univariant(&mut fields, &repr)?;
+                Ok(layout.union(&vlayout))
+            })?;
+            layout.pad_to_align(layout.align)
+        }
+
+        // Types with no meaningful known layout.
+        ty::Alias(..) => {
+            // NOTE(eddyb) `layout_of` query should've normalized these away,
+            // if that was possible, so there's no reason to try again here.
+            return Err(error(cx, LayoutError::Unknown(ty)));
+        }
+
+        ty::Bound(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) | ty::Infer(_) => {
+            bug!("Layout::compute: unexpected type `{}`", ty)
+        }
+
+        ty::Placeholder(..) | ty::Param(_) | ty::Error(_) => {
+            return Err(error(cx, LayoutError::Unknown(ty)));
+        }
+    })
+}
diff --git a/compiler/rustc_ty_utils/src/layout_sanity_check.rs b/compiler/rustc_ty_utils/src/layout_sanity_check.rs
index 8633334381a..2e3fe4e7fb8 100644
--- a/compiler/rustc_ty_utils/src/layout_sanity_check.rs
+++ b/compiler/rustc_ty_utils/src/layout_sanity_check.rs
@@ -1,5 +1,5 @@
 use rustc_middle::ty::{
-    layout::{LayoutCx, TyAndLayout},
+    layout::{LayoutCx, NaiveLayout, TyAndLayout},
     TyCtxt,
 };
 use rustc_target::abi::*;
@@ -10,6 +10,7 @@ use std::assert_matches::assert_matches;
 pub(super) fn sanity_check_layout<'tcx>(
     cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
     layout: &TyAndLayout<'tcx>,
+    naive: &NaiveLayout,
 ) {
     // Type-level uninhabitedness should always imply ABI uninhabitedness.
     if layout.ty.is_privately_uninhabited(cx.tcx, cx.param_env) {
@@ -20,6 +21,10 @@ pub(super) fn sanity_check_layout<'tcx>(
         bug!("size is not a multiple of align, in the following layout:\n{layout:#?}");
     }
 
+    if !naive.is_refined_by(layout.layout) {
+        bug!("the naive layout isn't refined by the actual layout:\n{:#?}\n{:#?}", naive, layout);
+    }
+
     if !cfg!(debug_assertions) {
         // Stop here, the rest is kind of expensive.
         return;
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 55b8857ed39..e2db6a6993f 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -31,6 +31,7 @@ mod errors;
 mod implied_bounds;
 pub mod instance;
 mod layout;
+mod layout_naive;
 mod layout_sanity_check;
 mod needs_drop;
 mod opaque_types;
@@ -47,6 +48,7 @@ pub fn provide(providers: &mut Providers) {
     consts::provide(providers);
     implied_bounds::provide(providers);
     layout::provide(providers);
+    layout_naive::provide(providers);
     needs_drop::provide(providers);
     opaque_types::provide(providers);
     representability::provide(providers);