Auto merge of #94690 - nnethercote:clarify-Layout-interning, r=fee1-dead
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. r? `@fee1-dead`
This commit is contained in:
commit
ecb867ec3c
17 changed files with 177 additions and 87 deletions
|
@ -82,8 +82,14 @@ pub(super) fn add_local_place_comments<'tcx>(
|
|||
return;
|
||||
}
|
||||
let TyAndLayout { ty, layout } = place.layout();
|
||||
let rustc_target::abi::Layout { size, align, abi: _, variants: _, fields: _, largest_niche: _ } =
|
||||
layout;
|
||||
let rustc_target::abi::LayoutS {
|
||||
size,
|
||||
align,
|
||||
abi: _,
|
||||
variants: _,
|
||||
fields: _,
|
||||
largest_niche: _,
|
||||
} = layout.0.0;
|
||||
|
||||
let (kind, extra) = match *place.inner() {
|
||||
CPlaceInner::Var(place_local, var) => {
|
||||
|
|
|
@ -1070,7 +1070,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
};
|
||||
|
||||
raw_eq, (v lhs_ref, v rhs_ref) {
|
||||
let size = fx.layout_of(substs.type_at(0)).layout.size;
|
||||
let size = fx.layout_of(substs.type_at(0)).layout.size();
|
||||
// FIXME add and use emit_small_memcmp
|
||||
let is_eq_value =
|
||||
if size == Size::ZERO {
|
||||
|
|
|
@ -272,20 +272,20 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
use rustc_target::abi::Abi::*;
|
||||
let tp_ty = substs.type_at(0);
|
||||
let layout = self.layout_of(tp_ty).layout;
|
||||
let _use_integer_compare = match layout.abi {
|
||||
let _use_integer_compare = match layout.abi() {
|
||||
Scalar(_) | ScalarPair(_, _) => true,
|
||||
Uninhabited | Vector { .. } => false,
|
||||
Aggregate { .. } => {
|
||||
// For rusty ABIs, small aggregates are actually passed
|
||||
// as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
|
||||
// so we re-use that same threshold here.
|
||||
layout.size <= self.data_layout().pointer_size * 2
|
||||
layout.size() <= self.data_layout().pointer_size * 2
|
||||
}
|
||||
};
|
||||
|
||||
let a = args[0].immediate();
|
||||
let b = args[1].immediate();
|
||||
if layout.size.bytes() == 0 {
|
||||
if layout.size().bytes() == 0 {
|
||||
self.const_bool(true)
|
||||
}
|
||||
/*else if use_integer_compare {
|
||||
|
@ -301,7 +301,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
let void_ptr_type = self.context.new_type::<*const ()>();
|
||||
let a_ptr = self.bitcast(a, void_ptr_type);
|
||||
let b_ptr = self.bitcast(b, void_ptr_type);
|
||||
let n = self.context.new_cast(None, self.const_usize(layout.size.bytes()), self.sizet_type);
|
||||
let n = self.context.new_cast(None, self.const_usize(layout.size().bytes()), self.sizet_type);
|
||||
let builtin = self.context.get_builtin_function("memcmp");
|
||||
let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]);
|
||||
self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
|
||||
|
|
|
@ -300,34 +300,34 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
use abi::Abi::*;
|
||||
let tp_ty = substs.type_at(0);
|
||||
let layout = self.layout_of(tp_ty).layout;
|
||||
let use_integer_compare = match layout.abi {
|
||||
let use_integer_compare = match layout.abi() {
|
||||
Scalar(_) | ScalarPair(_, _) => true,
|
||||
Uninhabited | Vector { .. } => false,
|
||||
Aggregate { .. } => {
|
||||
// For rusty ABIs, small aggregates are actually passed
|
||||
// as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
|
||||
// so we re-use that same threshold here.
|
||||
layout.size <= self.data_layout().pointer_size * 2
|
||||
layout.size() <= self.data_layout().pointer_size * 2
|
||||
}
|
||||
};
|
||||
|
||||
let a = args[0].immediate();
|
||||
let b = args[1].immediate();
|
||||
if layout.size.bytes() == 0 {
|
||||
if layout.size().bytes() == 0 {
|
||||
self.const_bool(true)
|
||||
} else if use_integer_compare {
|
||||
let integer_ty = self.type_ix(layout.size.bits());
|
||||
let integer_ty = self.type_ix(layout.size().bits());
|
||||
let ptr_ty = self.type_ptr_to(integer_ty);
|
||||
let a_ptr = self.bitcast(a, ptr_ty);
|
||||
let a_val = self.load(integer_ty, a_ptr, layout.align.abi);
|
||||
let a_val = self.load(integer_ty, a_ptr, layout.align().abi);
|
||||
let b_ptr = self.bitcast(b, ptr_ty);
|
||||
let b_val = self.load(integer_ty, b_ptr, layout.align.abi);
|
||||
let b_val = self.load(integer_ty, b_ptr, layout.align().abi);
|
||||
self.icmp(IntPredicate::IntEQ, a_val, b_val)
|
||||
} else {
|
||||
let i8p_ty = self.type_i8p();
|
||||
let a_ptr = self.bitcast(a, i8p_ty);
|
||||
let b_ptr = self.bitcast(b, i8p_ty);
|
||||
let n = self.const_usize(layout.size.bytes());
|
||||
let n = self.const_usize(layout.size().bytes());
|
||||
let cmp = self.call_intrinsic("memcmp", &[a_ptr, b_ptr, n]);
|
||||
self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
|
||||
}
|
||||
|
|
|
@ -427,7 +427,7 @@ fn push_debuginfo_type_name<'tcx>(
|
|||
|
||||
// calculate the range of values for the dataful variant
|
||||
let dataful_discriminant_range =
|
||||
dataful_variant_layout.largest_niche.unwrap().scalar.valid_range;
|
||||
dataful_variant_layout.largest_niche().unwrap().scalar.valid_range;
|
||||
|
||||
let min = dataful_discriminant_range.start;
|
||||
let min = tag.value.size(&tcx).truncate(min);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::stable_hasher::{HashStable, StableHasher};
|
||||
use std::cmp::Ordering;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::Deref;
|
||||
|
@ -98,5 +99,14 @@ impl<'a, T> Hash for Interned<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, CTX> HashStable<CTX> for Interned<'_, T>
|
||||
where
|
||||
T: HashStable<CTX>,
|
||||
{
|
||||
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
|
||||
self.0.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
|
@ -2861,8 +2861,8 @@ impl ClashingExternDeclarations {
|
|||
|
||||
let compare_layouts = |a, b| -> Result<bool, LayoutError<'tcx>> {
|
||||
debug!("compare_layouts({:?}, {:?})", a, b);
|
||||
let a_layout = &cx.layout_of(a)?.layout.abi;
|
||||
let b_layout = &cx.layout_of(b)?.layout.abi;
|
||||
let a_layout = &cx.layout_of(a)?.layout.abi();
|
||||
let b_layout = &cx.layout_of(b)?.layout.abi();
|
||||
debug!(
|
||||
"comparing layouts: {:?} == {:?} = {}",
|
||||
a_layout,
|
||||
|
|
|
@ -1349,7 +1349,7 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
|
|||
let (largest, slargest, largest_index) = iter::zip(enum_definition.variants, variants)
|
||||
.map(|(variant, variant_layout)| {
|
||||
// Subtract the size of the enum tag.
|
||||
let bytes = variant_layout.size.bytes().saturating_sub(tag_size);
|
||||
let bytes = variant_layout.size().bytes().saturating_sub(tag_size);
|
||||
|
||||
debug!("- variant `{}` is {} bytes large", variant.ident, bytes);
|
||||
bytes
|
||||
|
|
|
@ -392,7 +392,7 @@ impl Collector<'_> {
|
|||
.layout;
|
||||
// In both stdcall and fastcall, we always round up the argument size to the
|
||||
// nearest multiple of 4 bytes.
|
||||
(layout.size.bytes_usize() + 3) & !3
|
||||
(layout.size().bytes_usize() + 3) & !3
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
macro_rules! arena_types {
|
||||
($macro:path) => (
|
||||
$macro!([
|
||||
[] layout: rustc_target::abi::Layout,
|
||||
[] layout: rustc_target::abi::LayoutS<'tcx>,
|
||||
[] fn_abi: rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>,
|
||||
// AdtDef are interned and compared by address
|
||||
[decode] adt_def: rustc_middle::ty::AdtDef,
|
||||
|
|
|
@ -56,7 +56,7 @@ use rustc_span::def_id::{DefPathHash, StableCrateId};
|
|||
use rustc_span::source_map::{MultiSpan, SourceMap};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx};
|
||||
use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx};
|
||||
use rustc_target::spec::abi;
|
||||
|
||||
use rustc_type_ir::TypeFlags;
|
||||
|
@ -114,7 +114,7 @@ pub struct CtxtInterners<'tcx> {
|
|||
const_: InternedSet<'tcx, ConstS<'tcx>>,
|
||||
const_allocation: InternedSet<'tcx, Allocation>,
|
||||
bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
|
||||
layout: InternedSet<'tcx, Layout>,
|
||||
layout: InternedSet<'tcx, LayoutS<'tcx>>,
|
||||
adt_def: InternedSet<'tcx, AdtDef>,
|
||||
}
|
||||
|
||||
|
@ -2146,6 +2146,7 @@ direct_interners! {
|
|||
region: mk_region(RegionKind): Region -> Region<'tcx>,
|
||||
const_: mk_const(ConstS<'tcx>): Const -> Const<'tcx>,
|
||||
const_allocation: intern_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
|
||||
layout: intern_layout(LayoutS<'tcx>): Layout -> Layout<'tcx>,
|
||||
}
|
||||
|
||||
macro_rules! direct_interners_old {
|
||||
|
@ -2186,7 +2187,6 @@ macro_rules! direct_interners_old {
|
|||
|
||||
// FIXME: eventually these should all be converted to `direct_interners`.
|
||||
direct_interners_old! {
|
||||
layout: intern_layout(Layout),
|
||||
adt_def: intern_adt_def(AdtDef),
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -65,7 +65,7 @@ fn variant_discriminants<'tcx>(
|
|||
Variants::Multiple { variants, .. } => variants
|
||||
.iter_enumerated()
|
||||
.filter_map(|(idx, layout)| {
|
||||
(layout.abi != Abi::Uninhabited)
|
||||
(layout.abi() != Abi::Uninhabited)
|
||||
.then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val)
|
||||
})
|
||||
.collect(),
|
||||
|
|
|
@ -10,6 +10,7 @@ use std::num::NonZeroUsize;
|
|||
use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub};
|
||||
use std::str::FromStr;
|
||||
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_serialize::json::{Json, ToJson};
|
||||
|
@ -1024,7 +1025,7 @@ rustc_index::newtype_index! {
|
|||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
pub enum Variants {
|
||||
pub enum Variants<'a> {
|
||||
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
|
||||
Single { index: VariantIdx },
|
||||
|
||||
|
@ -1038,7 +1039,7 @@ pub enum Variants {
|
|||
tag: Scalar,
|
||||
tag_encoding: TagEncoding,
|
||||
tag_field: usize,
|
||||
variants: IndexVec<VariantIdx, Layout>,
|
||||
variants: IndexVec<VariantIdx, Layout<'a>>,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1146,8 +1147,8 @@ impl Niche {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
pub struct Layout {
|
||||
#[derive(PartialEq, Eq, Hash, HashStable_Generic)]
|
||||
pub struct LayoutS<'a> {
|
||||
/// Says where the fields are located within the layout.
|
||||
pub fields: FieldsShape,
|
||||
|
||||
|
@ -1158,7 +1159,7 @@ pub struct Layout {
|
|||
///
|
||||
/// To access all fields of this layout, both `fields` and the fields of the active variant
|
||||
/// must be taken into account.
|
||||
pub variants: Variants,
|
||||
pub variants: Variants<'a>,
|
||||
|
||||
/// The `abi` defines how this data is passed between functions, and it defines
|
||||
/// value restrictions via `valid_range`.
|
||||
|
@ -1177,12 +1178,12 @@ pub struct Layout {
|
|||
pub size: Size,
|
||||
}
|
||||
|
||||
impl Layout {
|
||||
impl<'a> LayoutS<'a> {
|
||||
pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
|
||||
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
|
||||
let size = scalar.value.size(cx);
|
||||
let align = scalar.value.align(cx);
|
||||
Layout {
|
||||
LayoutS {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldsShape::Primitive,
|
||||
abi: Abi::Scalar(scalar),
|
||||
|
@ -1193,6 +1194,59 @@ impl Layout {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for LayoutS<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// This is how `Layout` used to print before it become
|
||||
// `Interned<LayoutS>`. We print it like this to avoid having to update
|
||||
// expected output in a lot of tests.
|
||||
f.debug_struct("Layout")
|
||||
.field("fields", &self.fields)
|
||||
.field("variants", &self.variants)
|
||||
.field("abi", &self.abi)
|
||||
.field("largest_niche", &self.largest_niche)
|
||||
.field("align", &self.align)
|
||||
.field("size", &self.size)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
|
||||
#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
|
||||
pub struct Layout<'a>(pub Interned<'a, LayoutS<'a>>);
|
||||
|
||||
impl<'a> fmt::Debug for Layout<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// See comment on `<LayoutS as Debug>::fmt` above.
|
||||
self.0.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Layout<'a> {
|
||||
pub fn fields(self) -> &'a FieldsShape {
|
||||
&self.0.0.fields
|
||||
}
|
||||
|
||||
pub fn variants(self) -> &'a Variants<'a> {
|
||||
&self.0.0.variants
|
||||
}
|
||||
|
||||
pub fn abi(self) -> Abi {
|
||||
self.0.0.abi
|
||||
}
|
||||
|
||||
pub fn largest_niche(self) -> Option<Niche> {
|
||||
self.0.0.largest_niche
|
||||
}
|
||||
|
||||
pub fn align(self) -> AbiAndPrefAlign {
|
||||
self.0.0.align
|
||||
}
|
||||
|
||||
pub fn size(self) -> Size {
|
||||
self.0.0.size
|
||||
}
|
||||
}
|
||||
|
||||
/// The layout of a type, alongside the type itself.
|
||||
/// Provides various type traversal APIs (e.g., recursing into fields).
|
||||
///
|
||||
|
@ -1203,13 +1257,13 @@ impl Layout {
|
|||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)]
|
||||
pub struct TyAndLayout<'a, Ty> {
|
||||
pub ty: Ty,
|
||||
pub layout: &'a Layout,
|
||||
pub layout: Layout<'a>,
|
||||
}
|
||||
|
||||
impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
|
||||
type Target = &'a Layout;
|
||||
fn deref(&self) -> &&'a Layout {
|
||||
&self.layout
|
||||
type Target = &'a LayoutS<'a>;
|
||||
fn deref(&self) -> &&'a LayoutS<'a> {
|
||||
&self.layout.0.0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,13 +8,14 @@
|
|||
//! LLVM.
|
||||
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(let_else)]
|
||||
#![feature(nll)]
|
||||
#![feature(never_type)]
|
||||
#![feature(associated_type_bounds)]
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![feature(let_else)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(never_type)]
|
||||
#![feature(nll)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(step_trait)]
|
||||
|
||||
use std::iter::FromIterator;
|
||||
|
|
|
@ -1710,11 +1710,11 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) {
|
|||
}
|
||||
|
||||
fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
|
||||
fn write_size_of_layout(w: &mut Buffer, layout: &Layout, tag_size: u64) {
|
||||
if layout.abi.is_unsized() {
|
||||
fn write_size_of_layout(w: &mut Buffer, layout: Layout<'_>, tag_size: u64) {
|
||||
if layout.abi().is_unsized() {
|
||||
write!(w, "(unsized)");
|
||||
} else {
|
||||
let bytes = layout.size.bytes() - tag_size;
|
||||
let bytes = layout.size().bytes() - tag_size;
|
||||
write!(w, "{size} byte{pl}", size = bytes, pl = if bytes == 1 { "" } else { "s" },);
|
||||
}
|
||||
}
|
||||
|
@ -1744,7 +1744,7 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
|
|||
write_size_of_layout(w, ty_layout.layout, 0);
|
||||
writeln!(w, "</p>");
|
||||
if let Variants::Multiple { variants, tag, tag_encoding, .. } =
|
||||
&ty_layout.layout.variants
|
||||
&ty_layout.layout.variants()
|
||||
{
|
||||
if !variants.is_empty() {
|
||||
w.write_str(
|
||||
|
@ -1767,7 +1767,7 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
|
|||
for (index, layout) in variants.iter_enumerated() {
|
||||
let name = adt.variants[index].name;
|
||||
write!(w, "<li><code>{name}</code>: ", name = name);
|
||||
write_size_of_layout(w, layout, tag_size);
|
||||
write_size_of_layout(w, *layout, tag_size);
|
||||
writeln!(w, "</li>");
|
||||
}
|
||||
w.write_str("</ul>");
|
||||
|
|
|
@ -326,7 +326,7 @@ fn is_zero_sized_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||
if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty);
|
||||
if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
|
||||
then {
|
||||
layout.layout.size.bytes() == 0
|
||||
layout.layout.size().bytes() == 0
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue