Remove most manual LayoutData creations and move them to rustc_abi
...either as: - methods on LayoutCalculator, for faillible operations; - constructors on LayoutData, for infaillible ones.
This commit is contained in:
parent
cdd8af2299
commit
9917173575
6 changed files with 228 additions and 267 deletions
|
@ -12,6 +12,8 @@ use crate::{
|
||||||
Variants, WrappingRange,
|
Variants, WrappingRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod simple;
|
||||||
|
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
mod ty;
|
mod ty;
|
||||||
|
|
||||||
|
@ -102,41 +104,27 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
Self { cx }
|
Self { cx }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scalar_pair<FieldIdx: Idx, VariantIdx: Idx>(
|
pub fn array_like<FieldIdx: Idx, VariantIdx: Idx, F>(
|
||||||
&self,
|
&self,
|
||||||
a: Scalar,
|
element: &LayoutData<FieldIdx, VariantIdx>,
|
||||||
b: Scalar,
|
count_if_sized: Option<u64>, // None for slices
|
||||||
) -> LayoutData<FieldIdx, VariantIdx> {
|
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
|
||||||
let dl = self.cx.data_layout();
|
let count = count_if_sized.unwrap_or(0);
|
||||||
let b_align = b.align(dl);
|
let size =
|
||||||
let align = a.align(dl).max(b_align).max(dl.aggregate_align);
|
element.size.checked_mul(count, &self.cx).ok_or(LayoutCalculatorError::SizeOverflow)?;
|
||||||
let b_offset = a.size(dl).align_to(b_align.abi);
|
|
||||||
let size = (b_offset + b.size(dl)).align_to(align.abi);
|
|
||||||
|
|
||||||
// HACK(nox): We iter on `b` and then `a` because `max_by_key`
|
Ok(LayoutData {
|
||||||
// returns the last maximum.
|
|
||||||
let largest_niche = Niche::from_scalar(dl, b_offset, b)
|
|
||||||
.into_iter()
|
|
||||||
.chain(Niche::from_scalar(dl, Size::ZERO, a))
|
|
||||||
.max_by_key(|niche| niche.available(dl));
|
|
||||||
|
|
||||||
let combined_seed = a.size(&self.cx).bytes().wrapping_add(b.size(&self.cx).bytes());
|
|
||||||
|
|
||||||
LayoutData {
|
|
||||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||||
fields: FieldsShape::Arbitrary {
|
fields: FieldsShape::Array { stride: element.size, count },
|
||||||
offsets: [Size::ZERO, b_offset].into(),
|
backend_repr: BackendRepr::Memory { sized: count_if_sized.is_some() },
|
||||||
memory_index: [0, 1].into(),
|
largest_niche: element.largest_niche.filter(|_| count != 0),
|
||||||
},
|
uninhabited: element.uninhabited && count != 0,
|
||||||
backend_repr: BackendRepr::ScalarPair(a, b),
|
align: element.align,
|
||||||
largest_niche,
|
|
||||||
uninhabited: false,
|
|
||||||
align,
|
|
||||||
size,
|
size,
|
||||||
max_repr_align: None,
|
max_repr_align: None,
|
||||||
unadjusted_abi_align: align.abi,
|
unadjusted_abi_align: element.align.abi,
|
||||||
randomization_seed: Hash64::new(combined_seed),
|
randomization_seed: element.randomization_seed.wrapping_add(Hash64::new(count)),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn univariant<
|
pub fn univariant<
|
||||||
|
@ -214,25 +202,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
layout
|
layout
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layout_of_never_type<FieldIdx: Idx, VariantIdx: Idx>(
|
|
||||||
&self,
|
|
||||||
) -> LayoutData<FieldIdx, VariantIdx> {
|
|
||||||
let dl = self.cx.data_layout();
|
|
||||||
// This is also used for uninhabited enums, so we use `Variants::Empty`.
|
|
||||||
LayoutData {
|
|
||||||
variants: Variants::Empty,
|
|
||||||
fields: FieldsShape::Primitive,
|
|
||||||
backend_repr: BackendRepr::Memory { sized: true },
|
|
||||||
largest_niche: None,
|
|
||||||
uninhabited: true,
|
|
||||||
align: dl.i8_align,
|
|
||||||
size: Size::ZERO,
|
|
||||||
max_repr_align: None,
|
|
||||||
unadjusted_abi_align: dl.i8_align.abi,
|
|
||||||
randomization_seed: Hash64::ZERO,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn layout_of_struct_or_enum<
|
pub fn layout_of_struct_or_enum<
|
||||||
'a,
|
'a,
|
||||||
FieldIdx: Idx,
|
FieldIdx: Idx,
|
||||||
|
@ -260,7 +229,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
Some(present_first) => present_first,
|
Some(present_first) => present_first,
|
||||||
// Uninhabited because it has no variants, or only absent ones.
|
// Uninhabited because it has no variants, or only absent ones.
|
||||||
None if is_enum => {
|
None if is_enum => {
|
||||||
return Ok(self.layout_of_never_type());
|
return Ok(LayoutData::never_type(&self.cx));
|
||||||
}
|
}
|
||||||
// If it's a struct, still compute a layout so that we can still compute the
|
// If it's a struct, still compute a layout so that we can still compute the
|
||||||
// field offsets.
|
// field offsets.
|
||||||
|
@ -949,7 +918,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
// Common prim might be uninit.
|
// Common prim might be uninit.
|
||||||
Scalar::Union { value: prim }
|
Scalar::Union { value: prim }
|
||||||
};
|
};
|
||||||
let pair = self.scalar_pair::<FieldIdx, VariantIdx>(tag, prim_scalar);
|
let pair =
|
||||||
|
LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, tag, prim_scalar);
|
||||||
let pair_offsets = match pair.fields {
|
let pair_offsets = match pair.fields {
|
||||||
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
|
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
|
||||||
assert_eq!(memory_index.raw, [0, 1]);
|
assert_eq!(memory_index.raw, [0, 1]);
|
||||||
|
@ -1341,7 +1311,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
||||||
} else {
|
} else {
|
||||||
((j, b), (i, a))
|
((j, b), (i, a))
|
||||||
};
|
};
|
||||||
let pair = self.scalar_pair::<FieldIdx, VariantIdx>(a, b);
|
let pair =
|
||||||
|
LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, a, b);
|
||||||
let pair_offsets = match pair.fields {
|
let pair_offsets = match pair.fields {
|
||||||
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
|
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
|
||||||
assert_eq!(memory_index.raw, [0, 1]);
|
assert_eq!(memory_index.raw, [0, 1]);
|
||||||
|
|
148
compiler/rustc_abi/src/layout/simple.rs
Normal file
148
compiler/rustc_abi/src/layout/simple.rs
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
use std::num::NonZero;
|
||||||
|
|
||||||
|
use rustc_hashes::Hash64;
|
||||||
|
use rustc_index::{Idx, IndexVec};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
BackendRepr, FieldsShape, HasDataLayout, LayoutData, Niche, Primitive, Scalar, Size, Variants,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// "Simple" layout constructors that cannot fail.
|
||||||
|
impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
||||||
|
pub fn unit<C: HasDataLayout>(cx: &C, sized: bool) -> Self {
|
||||||
|
let dl = cx.data_layout();
|
||||||
|
LayoutData {
|
||||||
|
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||||
|
fields: FieldsShape::Arbitrary {
|
||||||
|
offsets: IndexVec::new(),
|
||||||
|
memory_index: IndexVec::new(),
|
||||||
|
},
|
||||||
|
backend_repr: BackendRepr::Memory { sized },
|
||||||
|
largest_niche: None,
|
||||||
|
uninhabited: false,
|
||||||
|
align: dl.i8_align,
|
||||||
|
size: Size::ZERO,
|
||||||
|
max_repr_align: None,
|
||||||
|
unadjusted_abi_align: dl.i8_align.abi,
|
||||||
|
randomization_seed: Hash64::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn never_type<C: HasDataLayout>(cx: &C) -> Self {
|
||||||
|
let dl = cx.data_layout();
|
||||||
|
// This is also used for uninhabited enums, so we use `Variants::Empty`.
|
||||||
|
LayoutData {
|
||||||
|
variants: Variants::Empty,
|
||||||
|
fields: FieldsShape::Primitive,
|
||||||
|
backend_repr: BackendRepr::Memory { sized: true },
|
||||||
|
largest_niche: None,
|
||||||
|
uninhabited: true,
|
||||||
|
align: dl.i8_align,
|
||||||
|
size: Size::ZERO,
|
||||||
|
max_repr_align: None,
|
||||||
|
unadjusted_abi_align: dl.i8_align.abi,
|
||||||
|
randomization_seed: Hash64::ZERO,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
|
||||||
|
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
|
||||||
|
let size = scalar.size(cx);
|
||||||
|
let align = scalar.align(cx);
|
||||||
|
|
||||||
|
let range = scalar.valid_range(cx);
|
||||||
|
|
||||||
|
// All primitive types for which we don't have subtype coercions should get a distinct seed,
|
||||||
|
// so that types wrapping them can use randomization to arrive at distinct layouts.
|
||||||
|
//
|
||||||
|
// Some type information is already lost at this point, so as an approximation we derive
|
||||||
|
// the seed from what remains. For example on 64-bit targets usize and u64 can no longer
|
||||||
|
// be distinguished.
|
||||||
|
let randomization_seed = size
|
||||||
|
.bytes()
|
||||||
|
.wrapping_add(
|
||||||
|
match scalar.primitive() {
|
||||||
|
Primitive::Int(_, true) => 1,
|
||||||
|
Primitive::Int(_, false) => 2,
|
||||||
|
Primitive::Float(_) => 3,
|
||||||
|
Primitive::Pointer(_) => 4,
|
||||||
|
} << 32,
|
||||||
|
)
|
||||||
|
// distinguishes references from pointers
|
||||||
|
.wrapping_add((range.start as u64).rotate_right(16))
|
||||||
|
// distinguishes char from u32 and bool from u8
|
||||||
|
.wrapping_add((range.end as u64).rotate_right(16));
|
||||||
|
|
||||||
|
LayoutData {
|
||||||
|
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||||
|
fields: FieldsShape::Primitive,
|
||||||
|
backend_repr: BackendRepr::Scalar(scalar),
|
||||||
|
largest_niche,
|
||||||
|
uninhabited: false,
|
||||||
|
size,
|
||||||
|
align,
|
||||||
|
max_repr_align: None,
|
||||||
|
unadjusted_abi_align: align.abi,
|
||||||
|
randomization_seed: Hash64::new(randomization_seed),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scalar_pair<C: HasDataLayout>(cx: &C, a: Scalar, b: Scalar) -> Self {
|
||||||
|
let dl = cx.data_layout();
|
||||||
|
let b_align = b.align(dl);
|
||||||
|
let align = a.align(dl).max(b_align).max(dl.aggregate_align);
|
||||||
|
let b_offset = a.size(dl).align_to(b_align.abi);
|
||||||
|
let size = (b_offset + b.size(dl)).align_to(align.abi);
|
||||||
|
|
||||||
|
// HACK(nox): We iter on `b` and then `a` because `max_by_key`
|
||||||
|
// returns the last maximum.
|
||||||
|
let largest_niche = Niche::from_scalar(dl, b_offset, b)
|
||||||
|
.into_iter()
|
||||||
|
.chain(Niche::from_scalar(dl, Size::ZERO, a))
|
||||||
|
.max_by_key(|niche| niche.available(dl));
|
||||||
|
|
||||||
|
let combined_seed = a.size(dl).bytes().wrapping_add(b.size(dl).bytes());
|
||||||
|
|
||||||
|
LayoutData {
|
||||||
|
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||||
|
fields: FieldsShape::Arbitrary {
|
||||||
|
offsets: [Size::ZERO, b_offset].into(),
|
||||||
|
memory_index: [0, 1].into(),
|
||||||
|
},
|
||||||
|
backend_repr: BackendRepr::ScalarPair(a, b),
|
||||||
|
largest_niche,
|
||||||
|
uninhabited: false,
|
||||||
|
align,
|
||||||
|
size,
|
||||||
|
max_repr_align: None,
|
||||||
|
unadjusted_abi_align: align.abi,
|
||||||
|
randomization_seed: Hash64::new(combined_seed),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a dummy layout for an uninhabited variant.
|
||||||
|
///
|
||||||
|
/// Uninhabited variants get pruned as part of the layout calculation,
|
||||||
|
/// so this can be used after the fact to reconstitute a layout.
|
||||||
|
pub fn uninhabited_variant<C: HasDataLayout>(cx: &C, index: VariantIdx, fields: usize) -> Self {
|
||||||
|
let dl = cx.data_layout();
|
||||||
|
LayoutData {
|
||||||
|
variants: Variants::Single { index },
|
||||||
|
fields: match NonZero::new(fields) {
|
||||||
|
Some(fields) => FieldsShape::Union(fields),
|
||||||
|
None => FieldsShape::Arbitrary {
|
||||||
|
offsets: IndexVec::new(),
|
||||||
|
memory_index: IndexVec::new(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
backend_repr: BackendRepr::Memory { sized: true },
|
||||||
|
largest_niche: None,
|
||||||
|
uninhabited: true,
|
||||||
|
align: dl.i8_align,
|
||||||
|
size: Size::ZERO,
|
||||||
|
max_repr_align: None,
|
||||||
|
unadjusted_abi_align: dl.i8_align.abi,
|
||||||
|
randomization_seed: Hash64::ZERO,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1744,48 +1744,6 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
||||||
pub fn is_uninhabited(&self) -> bool {
|
pub fn is_uninhabited(&self) -> bool {
|
||||||
self.uninhabited
|
self.uninhabited
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
|
|
||||||
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
|
|
||||||
let size = scalar.size(cx);
|
|
||||||
let align = scalar.align(cx);
|
|
||||||
|
|
||||||
let range = scalar.valid_range(cx);
|
|
||||||
|
|
||||||
// All primitive types for which we don't have subtype coercions should get a distinct seed,
|
|
||||||
// so that types wrapping them can use randomization to arrive at distinct layouts.
|
|
||||||
//
|
|
||||||
// Some type information is already lost at this point, so as an approximation we derive
|
|
||||||
// the seed from what remains. For example on 64-bit targets usize and u64 can no longer
|
|
||||||
// be distinguished.
|
|
||||||
let randomization_seed = size
|
|
||||||
.bytes()
|
|
||||||
.wrapping_add(
|
|
||||||
match scalar.primitive() {
|
|
||||||
Primitive::Int(_, true) => 1,
|
|
||||||
Primitive::Int(_, false) => 2,
|
|
||||||
Primitive::Float(_) => 3,
|
|
||||||
Primitive::Pointer(_) => 4,
|
|
||||||
} << 32,
|
|
||||||
)
|
|
||||||
// distinguishes references from pointers
|
|
||||||
.wrapping_add((range.start as u64).rotate_right(16))
|
|
||||||
// distinguishes char from u32 and bool from u8
|
|
||||||
.wrapping_add((range.end as u64).rotate_right(16));
|
|
||||||
|
|
||||||
LayoutData {
|
|
||||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
|
||||||
fields: FieldsShape::Primitive,
|
|
||||||
backend_repr: BackendRepr::Scalar(scalar),
|
|
||||||
largest_niche,
|
|
||||||
uninhabited: false,
|
|
||||||
size,
|
|
||||||
align,
|
|
||||||
max_repr_align: None,
|
|
||||||
unadjusted_abi_align: align.abi,
|
|
||||||
randomization_seed: Hash64::new(randomization_seed),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutData<FieldIdx, VariantIdx>
|
impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutData<FieldIdx, VariantIdx>
|
||||||
|
|
|
@ -1,20 +1,17 @@
|
||||||
use std::num::NonZero;
|
|
||||||
use std::ops::Bound;
|
use std::ops::Bound;
|
||||||
use std::{cmp, fmt};
|
use std::{cmp, fmt};
|
||||||
|
|
||||||
use rustc_abi::{
|
use rustc_abi::{
|
||||||
AddressSpace, Align, BackendRepr, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData,
|
AddressSpace, Align, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData, PointeeInfo,
|
||||||
PointeeInfo, PointerKind, Primitive, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout,
|
PointerKind, Primitive, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout,
|
||||||
TyAbiInterface, VariantIdx, Variants,
|
TyAbiInterface, VariantIdx, Variants,
|
||||||
};
|
};
|
||||||
use rustc_error_messages::DiagMessage;
|
use rustc_error_messages::DiagMessage;
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
|
Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
|
||||||
};
|
};
|
||||||
use rustc_hashes::Hash64;
|
|
||||||
use rustc_hir::LangItem;
|
use rustc_hir::LangItem;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_index::IndexVec;
|
|
||||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension};
|
use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension};
|
||||||
use rustc_session::config::OptLevel;
|
use rustc_session::config::OptLevel;
|
||||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
|
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
|
||||||
|
@ -762,11 +759,9 @@ where
|
||||||
variant_index: VariantIdx,
|
variant_index: VariantIdx,
|
||||||
) -> TyAndLayout<'tcx> {
|
) -> TyAndLayout<'tcx> {
|
||||||
let layout = match this.variants {
|
let layout = match this.variants {
|
||||||
Variants::Single { index }
|
|
||||||
// If all variants but one are uninhabited, the variant layout is the enum layout.
|
// If all variants but one are uninhabited, the variant layout is the enum layout.
|
||||||
if index == variant_index =>
|
Variants::Single { index } if index == variant_index => {
|
||||||
{
|
return this;
|
||||||
this.layout
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Variants::Single { .. } | Variants::Empty => {
|
Variants::Single { .. } | Variants::Empty => {
|
||||||
|
@ -783,29 +778,18 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
let fields = match this.ty.kind() {
|
let fields = match this.ty.kind() {
|
||||||
ty::Adt(def, _) if def.variants().is_empty() =>
|
ty::Adt(def, _) if def.variants().is_empty() => {
|
||||||
bug!("for_variant called on zero-variant enum {}", this.ty),
|
bug!("for_variant called on zero-variant enum {}", this.ty)
|
||||||
|
}
|
||||||
ty::Adt(def, _) => def.variant(variant_index).fields.len(),
|
ty::Adt(def, _) => def.variant(variant_index).fields.len(),
|
||||||
_ => bug!("`ty_and_layout_for_variant` on unexpected type {}", this.ty),
|
_ => bug!("`ty_and_layout_for_variant` on unexpected type {}", this.ty),
|
||||||
};
|
};
|
||||||
tcx.mk_layout(LayoutData {
|
tcx.mk_layout(LayoutData::uninhabited_variant(cx, variant_index, fields))
|
||||||
variants: Variants::Single { index: variant_index },
|
|
||||||
fields: match NonZero::new(fields) {
|
|
||||||
Some(fields) => FieldsShape::Union(fields),
|
|
||||||
None => FieldsShape::Arbitrary { offsets: IndexVec::new(), memory_index: IndexVec::new() },
|
|
||||||
},
|
|
||||||
backend_repr: BackendRepr::Memory { sized: true },
|
|
||||||
largest_niche: None,
|
|
||||||
uninhabited: true,
|
|
||||||
align: tcx.data_layout.i8_align,
|
|
||||||
size: Size::ZERO,
|
|
||||||
max_repr_align: None,
|
|
||||||
unadjusted_abi_align: tcx.data_layout.i8_align.abi,
|
|
||||||
randomization_seed: Hash64::ZERO,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Variants::Multiple { ref variants, .. } => cx.tcx().mk_layout(variants[variant_index].clone()),
|
Variants::Multiple { ref variants, .. } => {
|
||||||
|
cx.tcx().mk_layout(variants[variant_index].clone())
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(*layout.variants(), Variants::Single { index: variant_index });
|
assert_eq!(*layout.variants(), Variants::Single { index: variant_index });
|
||||||
|
|
|
@ -188,6 +188,10 @@ fn layout_of_uncached<'tcx>(
|
||||||
|
|
||||||
let tcx = cx.tcx();
|
let tcx = cx.tcx();
|
||||||
let dl = cx.data_layout();
|
let dl = cx.data_layout();
|
||||||
|
let map_layout = |result: Result<_, _>| match result {
|
||||||
|
Ok(layout) => Ok(tcx.mk_layout(layout)),
|
||||||
|
Err(err) => Err(map_error(cx, ty, err)),
|
||||||
|
};
|
||||||
let scalar_unit = |value: Primitive| {
|
let scalar_unit = |value: Primitive| {
|
||||||
let size = value.size(dl);
|
let size = value.size(dl);
|
||||||
assert!(size.bits() <= 128);
|
assert!(size.bits() <= 128);
|
||||||
|
@ -258,7 +262,7 @@ fn layout_of_uncached<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
// The never type.
|
// The never type.
|
||||||
ty::Never => tcx.mk_layout(cx.calc.layout_of_never_type()),
|
ty::Never => tcx.mk_layout(LayoutData::never_type(cx)),
|
||||||
|
|
||||||
// Potentially-wide pointers.
|
// Potentially-wide pointers.
|
||||||
ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
|
ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
|
||||||
|
@ -329,7 +333,7 @@ fn layout_of_uncached<'tcx>(
|
||||||
};
|
};
|
||||||
|
|
||||||
// Effectively a (ptr, meta) tuple.
|
// Effectively a (ptr, meta) tuple.
|
||||||
tcx.mk_layout(cx.calc.scalar_pair(data_ptr, metadata))
|
tcx.mk_layout(LayoutData::scalar_pair(cx, data_ptr, metadata))
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Dynamic(_, _, ty::DynStar) => {
|
ty::Dynamic(_, _, ty::DynStar) => {
|
||||||
|
@ -337,7 +341,7 @@ fn layout_of_uncached<'tcx>(
|
||||||
data.valid_range_mut().start = 0;
|
data.valid_range_mut().start = 0;
|
||||||
let mut vtable = scalar_unit(Pointer(AddressSpace::DATA));
|
let mut vtable = scalar_unit(Pointer(AddressSpace::DATA));
|
||||||
vtable.valid_range_mut().start = 1;
|
vtable.valid_range_mut().start = 1;
|
||||||
tcx.mk_layout(cx.calc.scalar_pair(data, vtable))
|
tcx.mk_layout(LayoutData::scalar_pair(cx, data, vtable))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arrays and slices.
|
// Arrays and slices.
|
||||||
|
@ -347,71 +351,29 @@ fn layout_of_uncached<'tcx>(
|
||||||
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
|
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
|
||||||
|
|
||||||
let element = cx.layout_of(element)?;
|
let element = cx.layout_of(element)?;
|
||||||
let size = element
|
map_layout(cx.calc.array_like(&element, Some(count)))?
|
||||||
.size
|
|
||||||
.checked_mul(count, dl)
|
|
||||||
.ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?;
|
|
||||||
|
|
||||||
let abi = BackendRepr::Memory { sized: true };
|
|
||||||
|
|
||||||
let largest_niche = if count != 0 { element.largest_niche } else { None };
|
|
||||||
let uninhabited = if count != 0 { element.uninhabited } else { false };
|
|
||||||
|
|
||||||
tcx.mk_layout(LayoutData {
|
|
||||||
variants: Variants::Single { index: FIRST_VARIANT },
|
|
||||||
fields: FieldsShape::Array { stride: element.size, count },
|
|
||||||
backend_repr: abi,
|
|
||||||
largest_niche,
|
|
||||||
uninhabited,
|
|
||||||
align: element.align,
|
|
||||||
size,
|
|
||||||
max_repr_align: None,
|
|
||||||
unadjusted_abi_align: element.align.abi,
|
|
||||||
randomization_seed: element.randomization_seed.wrapping_add(Hash64::new(count)),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
ty::Slice(element) => {
|
ty::Slice(element) => {
|
||||||
let element = cx.layout_of(element)?;
|
let element = cx.layout_of(element)?;
|
||||||
tcx.mk_layout(LayoutData {
|
map_layout(cx.calc.array_like(&element, None).map(|mut layout| {
|
||||||
variants: Variants::Single { index: FIRST_VARIANT },
|
// a randomly chosen value to distinguish slices
|
||||||
fields: FieldsShape::Array { stride: element.size, count: 0 },
|
layout.randomization_seed = Hash64::new(0x2dcba99c39784102);
|
||||||
backend_repr: BackendRepr::Memory { sized: false },
|
layout
|
||||||
largest_niche: None,
|
}))?
|
||||||
uninhabited: false,
|
|
||||||
align: element.align,
|
|
||||||
size: Size::ZERO,
|
|
||||||
max_repr_align: None,
|
|
||||||
unadjusted_abi_align: element.align.abi,
|
|
||||||
// adding a randomly chosen value to distinguish slices
|
|
||||||
randomization_seed: element
|
|
||||||
.randomization_seed
|
|
||||||
.wrapping_add(Hash64::new(0x2dcba99c39784102)),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
ty::Str => tcx.mk_layout(LayoutData {
|
ty::Str => {
|
||||||
variants: Variants::Single { index: FIRST_VARIANT },
|
let element = scalar(Int(I8, false));
|
||||||
fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
|
map_layout(cx.calc.array_like(&element, None).map(|mut layout| {
|
||||||
backend_repr: BackendRepr::Memory { sized: false },
|
|
||||||
largest_niche: None,
|
|
||||||
uninhabited: false,
|
|
||||||
align: dl.i8_align,
|
|
||||||
size: Size::ZERO,
|
|
||||||
max_repr_align: None,
|
|
||||||
unadjusted_abi_align: dl.i8_align.abi,
|
|
||||||
// another random value
|
// another random value
|
||||||
randomization_seed: Hash64::new(0xc1325f37d127be22),
|
layout.randomization_seed = Hash64::new(0xc1325f37d127be22);
|
||||||
}),
|
layout
|
||||||
|
}))?
|
||||||
|
}
|
||||||
|
|
||||||
// Odd unit types.
|
// Odd unit types.
|
||||||
ty::FnDef(..) => univariant(IndexSlice::empty(), StructKind::AlwaysSized)?,
|
ty::FnDef(..) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => {
|
||||||
ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => {
|
let sized = matches!(ty.kind(), ty::FnDef(..));
|
||||||
let mut unit =
|
tcx.mk_layout(LayoutData::unit(cx, sized))
|
||||||
univariant_uninterned(cx, ty, IndexSlice::empty(), StructKind::AlwaysSized)?;
|
|
||||||
match unit.backend_repr {
|
|
||||||
BackendRepr::Memory { ref mut sized } => *sized = false,
|
|
||||||
_ => bug!(),
|
|
||||||
}
|
|
||||||
tcx.mk_layout(unit)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Coroutine(def_id, args) => coroutine_layout(cx, ty, def_id, args)?,
|
ty::Coroutine(def_id, args) => coroutine_layout(cx, ty, def_id, args)?,
|
||||||
|
@ -545,11 +507,7 @@ fn layout_of_uncached<'tcx>(
|
||||||
return Err(error(cx, LayoutError::ReferencesError(guar)));
|
return Err(error(cx, LayoutError::ReferencesError(guar)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(tcx.mk_layout(
|
return map_layout(cx.calc.layout_of_union(&def.repr(), &variants));
|
||||||
cx.calc
|
|
||||||
.layout_of_union(&def.repr(), &variants)
|
|
||||||
.map_err(|err| map_error(cx, ty, err))?,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let get_discriminant_type =
|
let get_discriminant_type =
|
||||||
|
|
|
@ -15,7 +15,7 @@ use hir_def::{
|
||||||
use la_arena::{Idx, RawIdx};
|
use la_arena::{Idx, RawIdx};
|
||||||
use rustc_abi::AddressSpace;
|
use rustc_abi::AddressSpace;
|
||||||
use rustc_hashes::Hash64;
|
use rustc_hashes::Hash64;
|
||||||
use rustc_index::{IndexSlice, IndexVec};
|
use rustc_index::IndexVec;
|
||||||
|
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
|
||||||
|
@ -190,7 +190,8 @@ pub fn layout_of_ty_query(
|
||||||
let dl = &*target;
|
let dl = &*target;
|
||||||
let cx = LayoutCx::new(dl);
|
let cx = LayoutCx::new(dl);
|
||||||
let ty = normalize(db, trait_env.clone(), ty);
|
let ty = normalize(db, trait_env.clone(), ty);
|
||||||
let result = match ty.kind(Interner) {
|
let kind = ty.kind(Interner);
|
||||||
|
let result = match kind {
|
||||||
TyKind::Adt(AdtId(def), subst) => {
|
TyKind::Adt(AdtId(def), subst) => {
|
||||||
if let hir_def::AdtId::StructId(s) = def {
|
if let hir_def::AdtId::StructId(s) = def {
|
||||||
let data = db.struct_data(*s);
|
let data = db.struct_data(*s);
|
||||||
|
@ -216,7 +217,7 @@ pub fn layout_of_ty_query(
|
||||||
valid_range: WrappingRange { start: 0, end: 0x10FFFF },
|
valid_range: WrappingRange { start: 0, end: 0x10FFFF },
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
chalk_ir::Scalar::Int(i) => scalar(
|
chalk_ir::Scalar::Int(i) => Layout::scalar(dl, scalar_unit(
|
||||||
dl,
|
dl,
|
||||||
Primitive::Int(
|
Primitive::Int(
|
||||||
match i {
|
match i {
|
||||||
|
@ -229,8 +230,8 @@ pub fn layout_of_ty_query(
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
),
|
)),
|
||||||
chalk_ir::Scalar::Uint(i) => scalar(
|
chalk_ir::Scalar::Uint(i) => Layout::scalar(dl, scalar_unit(
|
||||||
dl,
|
dl,
|
||||||
Primitive::Int(
|
Primitive::Int(
|
||||||
match i {
|
match i {
|
||||||
|
@ -243,8 +244,8 @@ pub fn layout_of_ty_query(
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
),
|
)),
|
||||||
chalk_ir::Scalar::Float(f) => scalar(
|
chalk_ir::Scalar::Float(f) => Layout::scalar(dl, scalar_unit(
|
||||||
dl,
|
dl,
|
||||||
Primitive::Float(match f {
|
Primitive::Float(match f {
|
||||||
FloatTy::F16 => Float::F16,
|
FloatTy::F16 => Float::F16,
|
||||||
|
@ -252,7 +253,7 @@ pub fn layout_of_ty_query(
|
||||||
FloatTy::F64 => Float::F64,
|
FloatTy::F64 => Float::F64,
|
||||||
FloatTy::F128 => Float::F128,
|
FloatTy::F128 => Float::F128,
|
||||||
}),
|
}),
|
||||||
),
|
)),
|
||||||
},
|
},
|
||||||
TyKind::Tuple(len, tys) => {
|
TyKind::Tuple(len, tys) => {
|
||||||
let kind = if *len == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
|
let kind = if *len == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
|
||||||
|
@ -268,56 +269,16 @@ pub fn layout_of_ty_query(
|
||||||
TyKind::Array(element, count) => {
|
TyKind::Array(element, count) => {
|
||||||
let count = try_const_usize(db, count).ok_or(LayoutError::HasErrorConst)? as u64;
|
let count = try_const_usize(db, count).ok_or(LayoutError::HasErrorConst)? as u64;
|
||||||
let element = db.layout_of_ty(element.clone(), trait_env)?;
|
let element = db.layout_of_ty(element.clone(), trait_env)?;
|
||||||
let size = element
|
cx.calc.array_like::<_, _, ()>(&element, Some(count))?
|
||||||
.size
|
|
||||||
.checked_mul(count, dl)
|
|
||||||
.ok_or(LayoutError::BadCalc(LayoutCalculatorError::SizeOverflow))?;
|
|
||||||
|
|
||||||
let backend_repr = BackendRepr::Memory { sized: true };
|
|
||||||
|
|
||||||
let largest_niche = if count != 0 { element.largest_niche } else { None };
|
|
||||||
let uninhabited = if count != 0 { element.uninhabited } else { false };
|
|
||||||
|
|
||||||
Layout {
|
|
||||||
variants: Variants::Single { index: struct_variant_idx() },
|
|
||||||
fields: FieldsShape::Array { stride: element.size, count },
|
|
||||||
backend_repr,
|
|
||||||
largest_niche,
|
|
||||||
uninhabited,
|
|
||||||
align: element.align,
|
|
||||||
size,
|
|
||||||
max_repr_align: None,
|
|
||||||
unadjusted_abi_align: element.align.abi,
|
|
||||||
randomization_seed: Hash64::ZERO,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TyKind::Slice(element) => {
|
TyKind::Slice(element) => {
|
||||||
let element = db.layout_of_ty(element.clone(), trait_env)?;
|
let element = db.layout_of_ty(element.clone(), trait_env)?;
|
||||||
Layout {
|
cx.calc.array_like::<_, _, ()>(&element, None)?
|
||||||
variants: Variants::Single { index: struct_variant_idx() },
|
|
||||||
fields: FieldsShape::Array { stride: element.size, count: 0 },
|
|
||||||
backend_repr: BackendRepr::Memory { sized: false },
|
|
||||||
largest_niche: None,
|
|
||||||
uninhabited: false,
|
|
||||||
align: element.align,
|
|
||||||
size: Size::ZERO,
|
|
||||||
max_repr_align: None,
|
|
||||||
unadjusted_abi_align: element.align.abi,
|
|
||||||
randomization_seed: Hash64::ZERO,
|
|
||||||
}
|
}
|
||||||
|
TyKind::Str => {
|
||||||
|
let element = scalar_unit(dl, Primitive::Int(Integer::I8, false));
|
||||||
|
cx.calc.array_like::<_, _, ()>(&Layout::scalar(dl, element), None)?
|
||||||
}
|
}
|
||||||
TyKind::Str => Layout {
|
|
||||||
variants: Variants::Single { index: struct_variant_idx() },
|
|
||||||
fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
|
|
||||||
backend_repr: BackendRepr::Memory { sized: false },
|
|
||||||
largest_niche: None,
|
|
||||||
uninhabited: false,
|
|
||||||
align: dl.i8_align,
|
|
||||||
size: Size::ZERO,
|
|
||||||
max_repr_align: None,
|
|
||||||
unadjusted_abi_align: dl.i8_align.abi,
|
|
||||||
randomization_seed: Hash64::ZERO,
|
|
||||||
},
|
|
||||||
// Potentially-wide pointers.
|
// Potentially-wide pointers.
|
||||||
TyKind::Ref(_, _, pointee) | TyKind::Raw(_, pointee) => {
|
TyKind::Ref(_, _, pointee) | TyKind::Raw(_, pointee) => {
|
||||||
let mut data_ptr = scalar_unit(dl, Primitive::Pointer(AddressSpace::DATA));
|
let mut data_ptr = scalar_unit(dl, Primitive::Pointer(AddressSpace::DATA));
|
||||||
|
@ -355,17 +316,12 @@ pub fn layout_of_ty_query(
|
||||||
};
|
};
|
||||||
|
|
||||||
// Effectively a (ptr, meta) tuple.
|
// Effectively a (ptr, meta) tuple.
|
||||||
cx.calc.scalar_pair(data_ptr, metadata)
|
LayoutData::scalar_pair(dl, data_ptr, metadata)
|
||||||
}
|
}
|
||||||
TyKind::FnDef(_, _) => layout_of_unit(&cx)?,
|
TyKind::Never => LayoutData::never_type(dl),
|
||||||
TyKind::Never => cx.calc.layout_of_never_type(),
|
TyKind::FnDef(..) | TyKind::Dyn(_) | TyKind::Foreign(_) => {
|
||||||
TyKind::Dyn(_) | TyKind::Foreign(_) => {
|
let sized = matches!(kind, TyKind::FnDef(..));
|
||||||
let mut unit = layout_of_unit(&cx)?;
|
LayoutData::unit(dl, sized)
|
||||||
match &mut unit.backend_repr {
|
|
||||||
BackendRepr::Memory { sized } => *sized = false,
|
|
||||||
_ => return Err(LayoutError::Unknown),
|
|
||||||
}
|
|
||||||
unit
|
|
||||||
}
|
}
|
||||||
TyKind::Function(_) => {
|
TyKind::Function(_) => {
|
||||||
let mut ptr = scalar_unit(dl, Primitive::Pointer(dl.instruction_address_space));
|
let mut ptr = scalar_unit(dl, Primitive::Pointer(dl.instruction_address_space));
|
||||||
|
@ -434,16 +390,6 @@ pub fn layout_of_ty_recover(
|
||||||
Err(LayoutError::RecursiveTypeWithoutIndirection)
|
Err(LayoutError::RecursiveTypeWithoutIndirection)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout_of_unit(cx: &LayoutCx<'_>) -> Result<Layout, LayoutError> {
|
|
||||||
cx.calc
|
|
||||||
.univariant::<RustcFieldIdx, RustcEnumVariantIdx, &&Layout>(
|
|
||||||
IndexSlice::empty(),
|
|
||||||
&ReprOptions::default(),
|
|
||||||
StructKind::AlwaysSized,
|
|
||||||
)
|
|
||||||
.map_err(Into::into)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty {
|
fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty {
|
||||||
match pointee.kind(Interner) {
|
match pointee.kind(Interner) {
|
||||||
TyKind::Adt(AdtId(hir_def::AdtId::StructId(i)), subst) => {
|
TyKind::Adt(AdtId(hir_def::AdtId::StructId(i)), subst) => {
|
||||||
|
@ -474,9 +420,5 @@ fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar {
|
||||||
Scalar::Initialized { value, valid_range: WrappingRange::full(value.size(dl)) }
|
Scalar::Initialized { value, valid_range: WrappingRange::full(value.size(dl)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scalar(dl: &TargetDataLayout, value: Primitive) -> Layout {
|
|
||||||
Layout::scalar(dl, scalar_unit(dl, value))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue