Clarify Layout
interning.
`Layout` is another type that is sometimes interned, sometimes not, and we always use references to refer to it so we can't take any advantage of the uniqueness properties for hashing or equality checks. This commit renames `Layout` as `LayoutS`, and then introduces a new `Layout` that is a newtype around an `Interned<LayoutS>`. It also interns more layouts than before. Previously layouts within layouts (via the `variants` field) were never interned, but now they are. Hence the lifetime on the new `Layout` type. Unlike other interned types, these ones are in `rustc_target` instead of `rustc_middle`. This reflects the existing structure of the code, which does layout-specific stuff in `rustc_target` while `TyAndLayout` is generic over the `Ty`, allowing the type-specific stuff to occur in `rustc_middle`. The commit also adds a `HashStable` impl for `Interned`, which was needed. It hashes the contents, unlike the `Hash` impl which hashes the pointer.
This commit is contained in:
parent
8876ca3dd4
commit
4f008e06c3
17 changed files with 177 additions and 87 deletions
|
@ -5,6 +5,7 @@ use crate::ty::subst::Subst;
|
|||
use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_ast as ast;
|
||||
use rustc_attr as attr;
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
|
@ -302,7 +303,7 @@ fn invert_mapping(map: &[u32]) -> Vec<u32> {
|
|||
}
|
||||
|
||||
impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
||||
fn scalar_pair(&self, a: Scalar, b: Scalar) -> Layout {
|
||||
fn scalar_pair(&self, a: Scalar, b: Scalar) -> LayoutS<'tcx> {
|
||||
let dl = self.data_layout();
|
||||
let b_align = b.value.align(dl);
|
||||
let align = a.value.align(dl).max(b_align).max(dl.aggregate_align);
|
||||
|
@ -316,7 +317,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
.chain(Niche::from_scalar(dl, Size::ZERO, a))
|
||||
.max_by_key(|niche| niche.available(dl));
|
||||
|
||||
Layout {
|
||||
LayoutS {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldsShape::Arbitrary {
|
||||
offsets: vec![Size::ZERO, b_offset],
|
||||
|
@ -335,7 +336,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
fields: &[TyAndLayout<'_>],
|
||||
repr: &ReprOptions,
|
||||
kind: StructKind,
|
||||
) -> Result<Layout, LayoutError<'tcx>> {
|
||||
) -> Result<LayoutS<'tcx>, LayoutError<'tcx>> {
|
||||
let dl = self.data_layout();
|
||||
let pack = repr.pack;
|
||||
if pack.is_some() && repr.align.is_some() {
|
||||
|
@ -503,8 +504,20 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
|
||||
// Two non-ZST fields, and they're both scalars.
|
||||
(
|
||||
Some((i, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(a), .. }, .. })),
|
||||
Some((j, &TyAndLayout { layout: &Layout { abi: Abi::Scalar(b), .. }, .. })),
|
||||
Some((
|
||||
i,
|
||||
&TyAndLayout {
|
||||
layout: Layout(Interned(&LayoutS { abi: Abi::Scalar(a), .. }, _)),
|
||||
..
|
||||
},
|
||||
)),
|
||||
Some((
|
||||
j,
|
||||
&TyAndLayout {
|
||||
layout: Layout(Interned(&LayoutS { abi: Abi::Scalar(b), .. }, _)),
|
||||
..
|
||||
},
|
||||
)),
|
||||
None,
|
||||
) => {
|
||||
// Order by the memory placement, not source order.
|
||||
|
@ -537,7 +550,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
abi = Abi::Uninhabited;
|
||||
}
|
||||
|
||||
Ok(Layout {
|
||||
Ok(LayoutS {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldsShape::Arbitrary { offsets, memory_index },
|
||||
abi,
|
||||
|
@ -547,7 +560,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
})
|
||||
}
|
||||
|
||||
fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'tcx>> {
|
||||
fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
|
||||
let tcx = self.tcx;
|
||||
let param_env = self.param_env;
|
||||
let dl = self.data_layout();
|
||||
|
@ -556,7 +569,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
assert!(size.bits() <= 128);
|
||||
Scalar { value, valid_range: WrappingRange { start: 0, end: size.unsigned_int_max() } }
|
||||
};
|
||||
let scalar = |value: Primitive| tcx.intern_layout(Layout::scalar(self, scalar_unit(value)));
|
||||
let scalar =
|
||||
|value: Primitive| tcx.intern_layout(LayoutS::scalar(self, scalar_unit(value)));
|
||||
|
||||
let univariant = |fields: &[TyAndLayout<'_>], repr: &ReprOptions, kind| {
|
||||
Ok(tcx.intern_layout(self.univariant_uninterned(ty, fields, repr, kind)?))
|
||||
|
@ -565,11 +579,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
|
||||
Ok(match *ty.kind() {
|
||||
// Basic scalars.
|
||||
ty::Bool => tcx.intern_layout(Layout::scalar(
|
||||
ty::Bool => tcx.intern_layout(LayoutS::scalar(
|
||||
self,
|
||||
Scalar { value: Int(I8, false), valid_range: WrappingRange { start: 0, end: 1 } },
|
||||
)),
|
||||
ty::Char => tcx.intern_layout(Layout::scalar(
|
||||
ty::Char => tcx.intern_layout(LayoutS::scalar(
|
||||
self,
|
||||
Scalar {
|
||||
value: Int(I32, false),
|
||||
|
@ -585,11 +599,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
ty::FnPtr(_) => {
|
||||
let mut ptr = scalar_unit(Pointer);
|
||||
ptr.valid_range = ptr.valid_range.with_start(1);
|
||||
tcx.intern_layout(Layout::scalar(self, ptr))
|
||||
tcx.intern_layout(LayoutS::scalar(self, ptr))
|
||||
}
|
||||
|
||||
// The never type.
|
||||
ty::Never => tcx.intern_layout(Layout {
|
||||
ty::Never => tcx.intern_layout(LayoutS {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldsShape::Primitive,
|
||||
abi: Abi::Uninhabited,
|
||||
|
@ -607,13 +621,13 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
|
||||
let pointee = tcx.normalize_erasing_regions(param_env, pointee);
|
||||
if pointee.is_sized(tcx.at(DUMMY_SP), param_env) {
|
||||
return Ok(tcx.intern_layout(Layout::scalar(self, data_ptr)));
|
||||
return Ok(tcx.intern_layout(LayoutS::scalar(self, data_ptr)));
|
||||
}
|
||||
|
||||
let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
|
||||
let metadata = match unsized_part.kind() {
|
||||
ty::Foreign(..) => {
|
||||
return Ok(tcx.intern_layout(Layout::scalar(self, data_ptr)));
|
||||
return Ok(tcx.intern_layout(LayoutS::scalar(self, data_ptr)));
|
||||
}
|
||||
ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
|
||||
ty::Dynamic(..) => {
|
||||
|
@ -651,7 +665,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
|
||||
let largest_niche = if count != 0 { element.largest_niche } else { None };
|
||||
|
||||
tcx.intern_layout(Layout {
|
||||
tcx.intern_layout(LayoutS {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldsShape::Array { stride: element.size, count },
|
||||
abi,
|
||||
|
@ -662,7 +676,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
}
|
||||
ty::Slice(element) => {
|
||||
let element = self.layout_of(element)?;
|
||||
tcx.intern_layout(Layout {
|
||||
tcx.intern_layout(LayoutS {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldsShape::Array { stride: element.size, count: 0 },
|
||||
abi: Abi::Aggregate { sized: false },
|
||||
|
@ -671,7 +685,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
size: Size::ZERO,
|
||||
})
|
||||
}
|
||||
ty::Str => tcx.intern_layout(Layout {
|
||||
ty::Str => tcx.intern_layout(LayoutS {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
|
||||
abi: Abi::Aggregate { sized: false },
|
||||
|
@ -775,7 +789,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
|
||||
// Extract the number of elements from the layout of the array field:
|
||||
let Ok(TyAndLayout {
|
||||
layout: Layout { fields: FieldsShape::Array { count, .. }, .. },
|
||||
layout: Layout(Interned(LayoutS { fields: FieldsShape::Array { count, .. }, .. }, _)),
|
||||
..
|
||||
}) = self.layout_of(f0_ty) else {
|
||||
return Err(LayoutError::Unknown(ty));
|
||||
|
@ -825,7 +839,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
FieldsShape::Array { stride: e_ly.size, count: e_len }
|
||||
};
|
||||
|
||||
tcx.intern_layout(Layout {
|
||||
tcx.intern_layout(LayoutS {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields,
|
||||
abi: Abi::Vector { element: e_abi, count: e_len },
|
||||
|
@ -905,7 +919,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
align = align.min(AbiAndPrefAlign::new(pack));
|
||||
}
|
||||
|
||||
return Ok(tcx.intern_layout(Layout {
|
||||
return Ok(tcx.intern_layout(LayoutS {
|
||||
variants: Variants::Single { index },
|
||||
fields: FieldsShape::Union(
|
||||
NonZeroUsize::new(variants[index].len())
|
||||
|
@ -1100,17 +1114,17 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
|
||||
align = align.max(st.align);
|
||||
|
||||
Ok(st)
|
||||
Ok(tcx.intern_layout(st))
|
||||
})
|
||||
.collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
|
||||
|
||||
let offset = st[i].fields.offset(field_index) + niche.offset;
|
||||
let size = st[i].size;
|
||||
let offset = st[i].fields().offset(field_index) + niche.offset;
|
||||
let size = st[i].size();
|
||||
|
||||
let abi = if st.iter().all(|v| v.abi.is_uninhabited()) {
|
||||
let abi = if st.iter().all(|v| v.abi().is_uninhabited()) {
|
||||
Abi::Uninhabited
|
||||
} else {
|
||||
match st[i].abi {
|
||||
match st[i].abi() {
|
||||
Abi::Scalar(_) => Abi::Scalar(niche_scalar),
|
||||
Abi::ScalarPair(first, second) => {
|
||||
// We need to use scalar_unit to reset the
|
||||
|
@ -1130,7 +1144,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
|
||||
let largest_niche = Niche::from_scalar(dl, offset, niche_scalar);
|
||||
|
||||
niche_filling_layout = Some(Layout {
|
||||
niche_filling_layout = Some(LayoutS {
|
||||
variants: Variants::Multiple {
|
||||
tag: niche_scalar,
|
||||
tag_encoding: TagEncoding::Niche {
|
||||
|
@ -1377,7 +1391,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
|
||||
let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
|
||||
|
||||
let tagged_layout = Layout {
|
||||
let layout_variants =
|
||||
layout_variants.into_iter().map(|v| tcx.intern_layout(v)).collect();
|
||||
|
||||
let tagged_layout = LayoutS {
|
||||
variants: Variants::Multiple {
|
||||
tag,
|
||||
tag_encoding: TagEncoding::Direct,
|
||||
|
@ -1563,7 +1580,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
ty: Ty<'tcx>,
|
||||
def_id: hir::def_id::DefId,
|
||||
substs: SubstsRef<'tcx>,
|
||||
) -> Result<&'tcx Layout, LayoutError<'tcx>> {
|
||||
) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
|
||||
use SavedLocalEligibility::*;
|
||||
let tcx = self.tcx;
|
||||
let subst_field = |ty: Ty<'tcx>| ty.subst(tcx, substs);
|
||||
|
@ -1586,7 +1603,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
value: Primitive::Int(discr_int, false),
|
||||
valid_range: WrappingRange { start: 0, end: max_discr },
|
||||
};
|
||||
let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag));
|
||||
let tag_layout = self.tcx.intern_layout(LayoutS::scalar(self, tag));
|
||||
let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout };
|
||||
|
||||
let promoted_layouts = ineligible_locals
|
||||
|
@ -1722,20 +1739,20 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
|
||||
size = size.max(variant.size);
|
||||
align = align.max(variant.align);
|
||||
Ok(variant)
|
||||
Ok(tcx.intern_layout(variant))
|
||||
})
|
||||
.collect::<Result<IndexVec<VariantIdx, _>, _>>()?;
|
||||
|
||||
size = size.align_to(align.abi);
|
||||
|
||||
let abi = if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi.is_uninhabited())
|
||||
{
|
||||
Abi::Uninhabited
|
||||
} else {
|
||||
Abi::Aggregate { sized: true }
|
||||
};
|
||||
let abi =
|
||||
if prefix.abi.is_uninhabited() || variants.iter().all(|v| v.abi().is_uninhabited()) {
|
||||
Abi::Uninhabited
|
||||
} else {
|
||||
Abi::Aggregate { sized: true }
|
||||
};
|
||||
|
||||
let layout = tcx.intern_layout(Layout {
|
||||
let layout = tcx.intern_layout(LayoutS {
|
||||
variants: Variants::Multiple {
|
||||
tag,
|
||||
tag_encoding: TagEncoding::Direct,
|
||||
|
@ -2250,7 +2267,7 @@ where
|
|||
ty::Adt(def, _) => def.variants[variant_index].fields.len(),
|
||||
_ => bug!(),
|
||||
};
|
||||
tcx.intern_layout(Layout {
|
||||
tcx.intern_layout(LayoutS {
|
||||
variants: Variants::Single { index: variant_index },
|
||||
fields: match NonZeroUsize::new(fields) {
|
||||
Some(fields) => FieldsShape::Union(fields),
|
||||
|
@ -2263,10 +2280,10 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
Variants::Multiple { ref variants, .. } => &variants[variant_index],
|
||||
Variants::Multiple { ref variants, .. } => variants[variant_index],
|
||||
};
|
||||
|
||||
assert_eq!(layout.variants, Variants::Single { index: variant_index });
|
||||
assert_eq!(*layout.variants(), Variants::Single { index: variant_index });
|
||||
|
||||
TyAndLayout { ty: this.ty, layout }
|
||||
}
|
||||
|
@ -2284,8 +2301,10 @@ where
|
|||
) -> TyMaybeWithLayout<'tcx> {
|
||||
let tcx = cx.tcx();
|
||||
let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
|
||||
let layout = Layout::scalar(cx, tag);
|
||||
TyAndLayout { layout: tcx.intern_layout(layout), ty: tag.value.to_ty(tcx) }
|
||||
TyAndLayout {
|
||||
layout: tcx.intern_layout(LayoutS::scalar(cx, tag)),
|
||||
ty: tag.value.to_ty(tcx),
|
||||
}
|
||||
};
|
||||
|
||||
match *this.ty.kind() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue