Move naive_layout_of
query provider in separate sibling module
This commit is contained in:
parent
8e28729a82
commit
bf2f8ff2ec
4 changed files with 253 additions and 230 deletions
|
@ -5,8 +5,7 @@ use rustc_index::{IndexSlice, IndexVec};
|
||||||
use rustc_middle::mir::{GeneratorLayout, GeneratorSavedLocal};
|
use rustc_middle::mir::{GeneratorLayout, GeneratorSavedLocal};
|
||||||
use rustc_middle::query::{LocalCrate, Providers};
|
use rustc_middle::query::{LocalCrate, Providers};
|
||||||
use rustc_middle::ty::layout::{
|
use rustc_middle::ty::layout::{
|
||||||
IntegerExt, LayoutCx, LayoutError, LayoutOf, NaiveAbi, NaiveLayout, TyAndLayout,
|
IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
|
||||||
TyAndNaiveLayout, MAX_SIMD_LANES,
|
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, AdtDef, EarlyBinder, GenericArgsRef, ReprOptions, Ty, TyCtxt, TypeVisitableExt,
|
self, AdtDef, EarlyBinder, GenericArgsRef, ReprOptions, Ty, TyCtxt, TypeVisitableExt,
|
||||||
|
@ -25,7 +24,7 @@ use crate::errors::{
|
||||||
use crate::layout_sanity_check::sanity_check_layout;
|
use crate::layout_sanity_check::sanity_check_layout;
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers) {
|
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")]
|
#[instrument(skip(tcx), level = "debug")]
|
||||||
|
@ -37,40 +36,6 @@ fn reference_niches_policy<'tcx>(tcx: TyCtxt<'tcx>, _: LocalCrate) -> ReferenceN
|
||||||
/// crates not specifying `-Z reference-niches`.
|
/// crates not specifying `-Z reference-niches`.
|
||||||
const DEFAULT_REF_NICHES: ReferenceNichePolicy = ReferenceNichePolicy { size: false, align: false };
|
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")]
|
#[instrument(skip(tcx, query), level = "debug")]
|
||||||
fn layout_of<'tcx>(
|
fn layout_of<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
@ -90,13 +55,9 @@ fn layout_of<'tcx>(
|
||||||
let cx = LayoutCx { tcx, param_env };
|
let cx = LayoutCx { tcx, param_env };
|
||||||
let layout = layout_of_uncached(&cx, ty)?;
|
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 };
|
let layout = TyAndLayout { ty, layout };
|
||||||
record_layout_for_printing(&cx, layout);
|
record_layout_for_printing(&cx, layout);
|
||||||
sanity_check_layout(&cx, &layout);
|
sanity_check_layout(&cx, &layout, &naive);
|
||||||
|
|
||||||
Ok(layout)
|
Ok(layout)
|
||||||
}
|
}
|
||||||
|
@ -108,191 +69,6 @@ fn error<'tcx>(
|
||||||
cx.tcx.arena.alloc(err)
|
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>(
|
fn univariant_uninterned<'tcx>(
|
||||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||||
ty: Ty<'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>>,
|
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||||
mut count: ty::Const<'tcx>,
|
mut count: ty::Const<'tcx>,
|
||||||
) -> Option<u64> {
|
) -> Option<u64> {
|
||||||
|
@ -754,7 +530,7 @@ fn compute_array_count<'tcx>(
|
||||||
count.try_eval_target_usize(tcx, param_env)
|
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>>,
|
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||||
pointee: Ty<'tcx>,
|
pointee: Ty<'tcx>,
|
||||||
) -> Result<Option<Scalar>, &'tcx LayoutError<'tcx>> {
|
) -> Result<Option<Scalar>, &'tcx LayoutError<'tcx>> {
|
||||||
|
|
240
compiler/rustc_ty_utils/src/layout_naive.rs
Normal file
240
compiler/rustc_ty_utils/src/layout_naive.rs
Normal file
|
@ -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)));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
layout::{LayoutCx, TyAndLayout},
|
layout::{LayoutCx, NaiveLayout, TyAndLayout},
|
||||||
TyCtxt,
|
TyCtxt,
|
||||||
};
|
};
|
||||||
use rustc_target::abi::*;
|
use rustc_target::abi::*;
|
||||||
|
@ -10,6 +10,7 @@ use std::assert_matches::assert_matches;
|
||||||
pub(super) fn sanity_check_layout<'tcx>(
|
pub(super) fn sanity_check_layout<'tcx>(
|
||||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||||
layout: &TyAndLayout<'tcx>,
|
layout: &TyAndLayout<'tcx>,
|
||||||
|
naive: &NaiveLayout,
|
||||||
) {
|
) {
|
||||||
// Type-level uninhabitedness should always imply ABI uninhabitedness.
|
// Type-level uninhabitedness should always imply ABI uninhabitedness.
|
||||||
if layout.ty.is_privately_uninhabited(cx.tcx, cx.param_env) {
|
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:#?}");
|
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) {
|
if !cfg!(debug_assertions) {
|
||||||
// Stop here, the rest is kind of expensive.
|
// Stop here, the rest is kind of expensive.
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -31,6 +31,7 @@ mod errors;
|
||||||
mod implied_bounds;
|
mod implied_bounds;
|
||||||
pub mod instance;
|
pub mod instance;
|
||||||
mod layout;
|
mod layout;
|
||||||
|
mod layout_naive;
|
||||||
mod layout_sanity_check;
|
mod layout_sanity_check;
|
||||||
mod needs_drop;
|
mod needs_drop;
|
||||||
mod opaque_types;
|
mod opaque_types;
|
||||||
|
@ -47,6 +48,7 @@ pub fn provide(providers: &mut Providers) {
|
||||||
consts::provide(providers);
|
consts::provide(providers);
|
||||||
implied_bounds::provide(providers);
|
implied_bounds::provide(providers);
|
||||||
layout::provide(providers);
|
layout::provide(providers);
|
||||||
|
layout_naive::provide(providers);
|
||||||
needs_drop::provide(providers);
|
needs_drop::provide(providers);
|
||||||
opaque_types::provide(providers);
|
opaque_types::provide(providers);
|
||||||
representability::provide(providers);
|
representability::provide(providers);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue