mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-02 15:32:06 +00:00
Track ABI info. in NaiveLayout
, and use it for PointerLike
checks
THis significantly complicates `NaiveLayout` logic, but is necessary to ensure that bounds like `NonNull<T>: PointerLike` hold in generic contexts. Also implement exact layout computation for structs.
This commit is contained in:
parent
c30fbb95a6
commit
feb20f2fe7
@ -15,7 +15,7 @@ use rustc_target::abi::call::FnAbi;
|
|||||||
use rustc_target::abi::*;
|
use rustc_target::abi::*;
|
||||||
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
|
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
|
||||||
|
|
||||||
use std::cmp::{self, Ordering};
|
use std::cmp;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
use std::ops::Bound;
|
use std::ops::Bound;
|
||||||
@ -316,8 +316,8 @@ impl<'tcx> SizeSkeleton<'tcx> {
|
|||||||
// First, try computing an exact naive layout (this covers simple types with generic
|
// First, try computing an exact naive layout (this covers simple types with generic
|
||||||
// references, where a full static layout would fail).
|
// references, where a full static layout would fail).
|
||||||
if let Ok(layout) = tcx.naive_layout_of(param_env.and(ty)) {
|
if let Ok(layout) = tcx.naive_layout_of(param_env.and(ty)) {
|
||||||
if layout.is_exact {
|
if layout.exact {
|
||||||
return Ok(SizeSkeleton::Known(layout.min_size));
|
return Ok(SizeSkeleton::Known(layout.size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -650,51 +650,146 @@ impl std::ops::DerefMut for TyAndNaiveLayout<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A naive underestimation of the layout of a type.
|
/// Extremely simplified representation of a type's layout.
|
||||||
|
///
|
||||||
|
///
|
||||||
#[derive(Copy, Clone, Debug, HashStable)]
|
#[derive(Copy, Clone, Debug, HashStable)]
|
||||||
pub struct NaiveLayout {
|
pub struct NaiveLayout {
|
||||||
pub min_size: Size,
|
pub abi: NaiveAbi,
|
||||||
pub min_align: Align,
|
pub size: Size,
|
||||||
// If `true`, `min_size` and `min_align` are guaranteed to be exact.
|
pub align: Align,
|
||||||
pub is_exact: bool,
|
/// If `true`, `size` and `align` are exact.
|
||||||
|
pub exact: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable)]
|
||||||
|
pub enum NaiveAbi {
|
||||||
|
/// A scalar layout, always implies `exact`.
|
||||||
|
Scalar(Primitive),
|
||||||
|
/// An uninhabited layout. (needed to properly track `Scalar`)
|
||||||
|
Uninhabited,
|
||||||
|
/// An unsized aggregate. (needed to properly track `Scalar`)
|
||||||
|
Unsized,
|
||||||
|
Any,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NaiveAbi {
|
||||||
|
#[inline]
|
||||||
|
pub fn as_aggregate(self) -> Self {
|
||||||
|
match self {
|
||||||
|
NaiveAbi::Scalar(_) => NaiveAbi::Any,
|
||||||
|
_ => self,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NaiveLayout {
|
impl NaiveLayout {
|
||||||
pub const UNKNOWN: Self = Self { min_size: Size::ZERO, min_align: Align::ONE, is_exact: false };
|
pub const EMPTY: Self =
|
||||||
pub const EMPTY: Self = Self { min_size: Size::ZERO, min_align: Align::ONE, is_exact: true };
|
Self { size: Size::ZERO, align: Align::ONE, exact: true, abi: NaiveAbi::Any };
|
||||||
|
|
||||||
pub fn is_compatible_with(&self, layout: Layout<'_>) -> bool {
|
pub fn is_refined_by(&self, layout: Layout<'_>) -> bool {
|
||||||
let cmp = |cmp: Ordering| match (cmp, self.is_exact) {
|
if self.size > layout.size() || self.align > layout.align().abi {
|
||||||
(Ordering::Less | Ordering::Equal, false) => true,
|
return false;
|
||||||
(Ordering::Equal, true) => true,
|
}
|
||||||
(_, _) => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
cmp(self.min_size.cmp(&layout.size())) && cmp(self.min_align.cmp(&layout.align().abi))
|
if let NaiveAbi::Scalar(prim) = self.abi {
|
||||||
|
assert!(self.exact);
|
||||||
|
if !matches!(layout.abi(), Abi::Scalar(s) if s.primitive() == prim) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
!self.exact || (self.size, self.align) == (layout.size(), layout.align().abi)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns if this layout is known to be pointer-like (`None` if uncertain)
|
||||||
|
///
|
||||||
|
/// See the corresponding `Layout::is_pointer_like` method.
|
||||||
|
pub fn is_pointer_like(&self, dl: &TargetDataLayout) -> Option<bool> {
|
||||||
|
match self.abi {
|
||||||
|
NaiveAbi::Scalar(_) => {
|
||||||
|
assert!(self.exact);
|
||||||
|
Some(self.size == dl.pointer_size && self.align == dl.pointer_align.abi)
|
||||||
|
}
|
||||||
|
NaiveAbi::Uninhabited | NaiveAbi::Unsized => Some(false),
|
||||||
|
NaiveAbi::Any if self.exact => Some(false),
|
||||||
|
NaiveAbi::Any => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn pad_to_align(mut self) -> Self {
|
#[inline]
|
||||||
self.min_size = self.min_size.align_to(self.min_align);
|
pub fn packed(mut self, align: Align) -> Self {
|
||||||
|
if self.align > align {
|
||||||
|
self.align = align;
|
||||||
|
self.abi = self.abi.as_aggregate();
|
||||||
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn concat<C: HasDataLayout>(&self, other: &Self, cx: &C) -> Option<Self> {
|
#[inline]
|
||||||
Some(Self {
|
pub fn align_to(mut self, align: Align) -> Self {
|
||||||
min_size: self.min_size.checked_add(other.min_size, cx)?,
|
if align > self.align {
|
||||||
min_align: std::cmp::max(self.min_align, other.min_align),
|
self.align = align;
|
||||||
is_exact: self.is_exact && other.is_exact,
|
self.abi = self.abi.as_aggregate();
|
||||||
})
|
}
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn union(&self, other: &Self) -> Self {
|
#[inline]
|
||||||
Self {
|
pub fn pad_to_align(mut self, align: Align) -> Self {
|
||||||
min_size: std::cmp::max(self.min_size, other.min_size),
|
let new_size = self.size.align_to(align);
|
||||||
min_align: std::cmp::max(self.min_align, other.min_align),
|
if new_size > self.size {
|
||||||
is_exact: self.is_exact && other.is_exact,
|
self.abi = self.abi.as_aggregate();
|
||||||
|
self.size = new_size;
|
||||||
}
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
#[inline]
|
||||||
|
pub fn concat(&self, other: &Self, dl: &TargetDataLayout) -> Option<Self> {
|
||||||
|
use NaiveAbi::*;
|
||||||
|
|
||||||
|
let size = self.size.checked_add(other.size, dl)?;
|
||||||
|
let align = cmp::max(self.align, other.align);
|
||||||
|
let exact = self.exact && other.exact;
|
||||||
|
let abi = match (self.abi, other.abi) {
|
||||||
|
// The uninhabited and unsized ABIs override everything.
|
||||||
|
(Uninhabited, _) | (_, Uninhabited) => Uninhabited,
|
||||||
|
(Unsized, _) | (_, Unsized) => Unsized,
|
||||||
|
// A scalar struct must have a single non ZST-field.
|
||||||
|
(_, s @ Scalar(_)) if exact && self.size == Size::ZERO => s,
|
||||||
|
(s @ Scalar(_), _) if exact && other.size == Size::ZERO => s,
|
||||||
|
// Default case.
|
||||||
|
(_, _) => Any,
|
||||||
|
};
|
||||||
|
Some(Self { abi, size, align, exact })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
#[inline]
|
||||||
|
pub fn union(&self, other: &Self) -> Self {
|
||||||
|
use NaiveAbi::*;
|
||||||
|
|
||||||
|
let size = cmp::max(self.size, other.size);
|
||||||
|
let align = cmp::max(self.align, other.align);
|
||||||
|
let exact = self.exact && other.exact;
|
||||||
|
let abi = match (self.abi, other.abi) {
|
||||||
|
// The unsized ABI overrides everything.
|
||||||
|
(Unsized, _) | (_, Unsized) => Unsized,
|
||||||
|
// A scalar union must have a single non ZST-field.
|
||||||
|
(_, s @ Scalar(_)) if exact && self.size == Size::ZERO => s,
|
||||||
|
(s @ Scalar(_), _) if exact && other.size == Size::ZERO => s,
|
||||||
|
// ...or identical scalar fields.
|
||||||
|
(Scalar(s1), Scalar(s2)) if s1 == s2 => Scalar(s1),
|
||||||
|
// Default cases.
|
||||||
|
(Uninhabited, Uninhabited) => Uninhabited,
|
||||||
|
(_, _) => Any,
|
||||||
|
};
|
||||||
|
Self { abi, size, align, exact }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,9 +223,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
|
return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(layout) = tcx.layout_of(key)
|
// First, try computing an exact naive layout in case the type is generic.
|
||||||
&& layout.layout.is_pointer_like(&tcx.data_layout)
|
let is_pointer_like = if let Ok(layout) = tcx.naive_layout_of(key) {
|
||||||
{
|
layout.is_pointer_like(&tcx.data_layout).unwrap_or_else(|| {
|
||||||
|
// Second, we fall back to full layout computation.
|
||||||
|
tcx.layout_of(key)
|
||||||
|
.ok()
|
||||||
|
.filter(|l| l.layout.is_pointer_like(&tcx.data_layout))
|
||||||
|
.is_some()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if is_pointer_like {
|
||||||
// FIXME: We could make this faster by making a no-constraints response
|
// FIXME: We could make this faster by making a no-constraints response
|
||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
} else {
|
} else {
|
||||||
|
@ -979,9 +979,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(layout) = tcx.layout_of(key)
|
// First, try computing an exact naive layout in case the type is generic.
|
||||||
&& layout.layout.is_pointer_like(&tcx.data_layout)
|
let is_pointer_like = if let Ok(layout) = tcx.naive_layout_of(key) {
|
||||||
{
|
layout.is_pointer_like(&tcx.data_layout).unwrap_or_else(|| {
|
||||||
|
// Second, we fall back to full layout computation.
|
||||||
|
tcx.layout_of(key)
|
||||||
|
.ok()
|
||||||
|
.filter(|l| l.layout.is_pointer_like(&tcx.data_layout))
|
||||||
|
.is_some()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if is_pointer_like {
|
||||||
candidates.vec.push(BuiltinCandidate { has_nested: false });
|
candidates.vec.push(BuiltinCandidate { has_nested: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@ 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, NaiveLayout, TyAndLayout, TyAndNaiveLayout,
|
IntegerExt, LayoutCx, LayoutError, LayoutOf, NaiveAbi, NaiveLayout, 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,
|
||||||
@ -90,12 +90,8 @@ 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_compatible_with(layout) {
|
if !naive.is_refined_by(layout) {
|
||||||
bug!(
|
bug!("the naive layout isn't refined by the actual layout:\n{:#?}\n{:#?}", naive, layout,);
|
||||||
"the naive layout isn't compatible with the actual layout:\n{:#?}\n{:#?}",
|
|
||||||
naive,
|
|
||||||
layout,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let layout = TyAndLayout { ty, layout };
|
let layout = TyAndLayout { ty, layout };
|
||||||
@ -120,9 +116,10 @@ fn naive_layout_of_uncached<'tcx>(
|
|||||||
let dl = cx.data_layout();
|
let dl = cx.data_layout();
|
||||||
|
|
||||||
let scalar = |value: Primitive| NaiveLayout {
|
let scalar = |value: Primitive| NaiveLayout {
|
||||||
min_size: value.size(dl),
|
abi: NaiveAbi::Scalar(value),
|
||||||
min_align: value.align(dl).abi,
|
size: value.size(dl),
|
||||||
is_exact: true,
|
align: value.align(dl).abi,
|
||||||
|
exact: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
let univariant = |fields: &mut dyn Iterator<Item = Ty<'tcx>>,
|
let univariant = |fields: &mut dyn Iterator<Item = Ty<'tcx>>,
|
||||||
@ -133,24 +130,29 @@ fn naive_layout_of_uncached<'tcx>(
|
|||||||
return Err(error(cx, LayoutError::Unknown(ty)));
|
return Err(error(cx, LayoutError::Unknown(ty)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// For simplicity, ignore inter-field padding; this may underestimate the size.
|
let linear = repr.inhibit_struct_field_reordering_opt();
|
||||||
// FIXME(reference_niches): Be smarter and implement something closer to the real layout logic.
|
let pack = repr.pack.unwrap_or(Align::MAX);
|
||||||
let mut layout = NaiveLayout::UNKNOWN;
|
let mut layout = NaiveLayout::EMPTY;
|
||||||
|
|
||||||
for field in fields {
|
for field in fields {
|
||||||
let field = cx.naive_layout_of(field)?;
|
let field = cx.naive_layout_of(field)?.packed(pack);
|
||||||
|
if linear {
|
||||||
|
layout = layout.pad_to_align(field.align);
|
||||||
|
}
|
||||||
layout = layout
|
layout = layout
|
||||||
.concat(&field, cx)
|
.concat(&field, dl)
|
||||||
.ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?;
|
.ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(align) = repr.align {
|
if let Some(align) = repr.align {
|
||||||
layout.min_align = std::cmp::max(layout.min_align, align);
|
layout = layout.align_to(align);
|
||||||
}
|
|
||||||
if let Some(pack) = repr.pack {
|
|
||||||
layout.min_align = std::cmp::min(layout.min_align, pack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(layout.pad_to_align())
|
if linear {
|
||||||
|
layout.abi = layout.abi.as_aggregate();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(layout.pad_to_align(layout.align))
|
||||||
};
|
};
|
||||||
|
|
||||||
debug_assert!(!ty.has_non_region_infer());
|
debug_assert!(!ty.has_non_region_infer());
|
||||||
@ -168,17 +170,17 @@ fn naive_layout_of_uncached<'tcx>(
|
|||||||
ty::FnPtr(_) => scalar(Pointer(dl.instruction_address_space)),
|
ty::FnPtr(_) => scalar(Pointer(dl.instruction_address_space)),
|
||||||
|
|
||||||
// The never type.
|
// The never type.
|
||||||
ty::Never => NaiveLayout::EMPTY,
|
ty::Never => NaiveLayout { abi: NaiveAbi::Uninhabited, ..NaiveLayout::EMPTY },
|
||||||
|
|
||||||
// Potentially-wide pointers.
|
// Potentially-wide pointers.
|
||||||
ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
|
ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
|
||||||
let data_ptr = scalar(Pointer(AddressSpace::DATA));
|
let data_ptr = scalar(Pointer(AddressSpace::DATA));
|
||||||
if let Some(metadata) = ptr_metadata_scalar(cx, pointee)? {
|
if let Some(metadata) = ptr_metadata_scalar(cx, pointee)? {
|
||||||
// Effectively a (ptr, meta) tuple.
|
// Effectively a (ptr, meta) tuple.
|
||||||
data_ptr
|
let l = data_ptr
|
||||||
.concat(&scalar(metadata.primitive()), cx)
|
.concat(&scalar(metadata.primitive()), dl)
|
||||||
.ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?
|
.ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?;
|
||||||
.pad_to_align()
|
l.pad_to_align(l.align)
|
||||||
} else {
|
} else {
|
||||||
// No metadata, this is a thin pointer.
|
// No metadata, this is a thin pointer.
|
||||||
data_ptr
|
data_ptr
|
||||||
@ -187,7 +189,7 @@ fn naive_layout_of_uncached<'tcx>(
|
|||||||
|
|
||||||
ty::Dynamic(_, _, ty::DynStar) => {
|
ty::Dynamic(_, _, ty::DynStar) => {
|
||||||
let ptr = scalar(Pointer(AddressSpace::DATA));
|
let ptr = scalar(Pointer(AddressSpace::DATA));
|
||||||
ptr.concat(&ptr, cx).ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?
|
ptr.concat(&ptr, dl).ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arrays and slices.
|
// Arrays and slices.
|
||||||
@ -196,26 +198,29 @@ fn naive_layout_of_uncached<'tcx>(
|
|||||||
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
|
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
|
||||||
let element = cx.naive_layout_of(element)?;
|
let element = cx.naive_layout_of(element)?;
|
||||||
NaiveLayout {
|
NaiveLayout {
|
||||||
min_size: element
|
abi: element.abi.as_aggregate(),
|
||||||
.min_size
|
size: element
|
||||||
|
.size
|
||||||
.checked_mul(count, cx)
|
.checked_mul(count, cx)
|
||||||
.ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?,
|
.ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?,
|
||||||
..*element
|
..*element
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Slice(element) => NaiveLayout {
|
ty::Slice(element) => {
|
||||||
min_size: Size::ZERO,
|
let element = cx.naive_layout_of(element)?;
|
||||||
// NOTE: this could be unconditionally exact if `NaiveLayout` guaranteed exact align.
|
NaiveLayout { abi: NaiveAbi::Unsized, size: Size::ZERO, ..*element }
|
||||||
..*cx.naive_layout_of(element)?
|
}
|
||||||
},
|
|
||||||
ty::Str => NaiveLayout::EMPTY,
|
|
||||||
|
|
||||||
// Odd unit types.
|
ty::FnDef(..) => NaiveLayout::EMPTY,
|
||||||
ty::FnDef(..) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => 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,
|
// FIXME(reference_niches): try to actually compute a reasonable layout estimate,
|
||||||
// without duplicating too much code from `generator_layout`.
|
// without duplicating too much code from `generator_layout`.
|
||||||
ty::Generator(..) => NaiveLayout::UNKNOWN,
|
ty::Generator(..) => NaiveLayout { exact: false, ..NaiveLayout::EMPTY },
|
||||||
|
|
||||||
ty::Closure(_, ref substs) => {
|
ty::Closure(_, ref substs) => {
|
||||||
univariant(&mut substs.as_closure().upvar_tys(), &ReprOptions::default())?
|
univariant(&mut substs.as_closure().upvar_tys(), &ReprOptions::default())?
|
||||||
@ -225,33 +230,50 @@ fn naive_layout_of_uncached<'tcx>(
|
|||||||
|
|
||||||
ty::Adt(def, substs) if def.is_union() => {
|
ty::Adt(def, substs) if def.is_union() => {
|
||||||
let repr = def.repr();
|
let repr = def.repr();
|
||||||
let only_variant = &def.variants()[FIRST_VARIANT];
|
let pack = repr.pack.unwrap_or(Align::MAX);
|
||||||
only_variant.fields.iter().try_fold(NaiveLayout::EMPTY, |layout, f| {
|
if repr.pack.is_some() && repr.align.is_some() {
|
||||||
let mut fields = std::iter::once(f.ty(tcx, substs));
|
cx.tcx.sess.delay_span_bug(DUMMY_SP, "union cannot be packed and aligned");
|
||||||
univariant(&mut fields, &repr).map(|l| layout.union(&l))
|
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::Any;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(align) = repr.align {
|
||||||
|
layout = layout.align_to(align);
|
||||||
|
}
|
||||||
|
layout.pad_to_align(layout.align)
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Adt(def, substs) => {
|
ty::Adt(def, substs) => {
|
||||||
let repr = def.repr();
|
let repr = def.repr();
|
||||||
let base = if def.is_struct() && !repr.simd() {
|
let base = NaiveLayout {
|
||||||
// FIXME(reference_niches): compute proper alignment for SIMD types.
|
// For simplicity, assume that any enum has its discriminant field (if it exists)
|
||||||
NaiveLayout::EMPTY
|
// niched inside one of the variants; this will underestimate the size (and sometimes
|
||||||
} else {
|
// alignment) of enums. We also doesn't compute exact alignment for SIMD structs.
|
||||||
// For simplicity, assume that any discriminant field (if it exists)
|
// FIXME(reference_niches): Be smarter here.
|
||||||
// gets niched inside one of the variants; this will underestimate the size
|
|
||||||
// (and sometimes alignment) of enums.
|
|
||||||
// FIXME(reference_niches): Be smarter and actually take into accoount the discriminant.
|
|
||||||
// Also consider adding a special case for null-optimized enums, so that we can have
|
// Also consider adding a special case for null-optimized enums, so that we can have
|
||||||
// `Option<&T>: PointerLike` in generic contexts.
|
// `Option<&T>: PointerLike` in generic contexts.
|
||||||
NaiveLayout::UNKNOWN
|
exact: !def.is_enum() && !repr.simd(),
|
||||||
|
// An ADT with no inhabited variants should have an uninhabited ABI.
|
||||||
|
abi: NaiveAbi::Uninhabited,
|
||||||
|
..NaiveLayout::EMPTY
|
||||||
};
|
};
|
||||||
|
|
||||||
def.variants().iter().try_fold(base, |layout, v| {
|
let layout = def.variants().iter().try_fold(base, |layout, v| {
|
||||||
let mut fields = v.fields.iter().map(|f| f.ty(tcx, substs));
|
let mut fields = v.fields.iter().map(|f| f.ty(tcx, substs));
|
||||||
let vlayout = univariant(&mut fields, &repr)?;
|
let vlayout = univariant(&mut fields, &repr)?;
|
||||||
Ok(layout.union(&vlayout))
|
Ok(layout.union(&vlayout))
|
||||||
})?
|
})?;
|
||||||
|
layout.pad_to_align(layout.align)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Types with no meaningful known layout.
|
// Types with no meaningful known layout.
|
||||||
@ -354,8 +376,8 @@ fn layout_of_uncached<'tcx>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (min_addr, max_addr) = dl.address_range_for(
|
let (min_addr, max_addr) = dl.address_range_for(
|
||||||
if niches.size { naive.min_size } else { Size::ZERO },
|
if niches.size { naive.size } else { Size::ZERO },
|
||||||
if niches.align { naive.min_align } else { Align::ONE },
|
if niches.align { naive.align } else { Align::ONE },
|
||||||
);
|
);
|
||||||
|
|
||||||
*data_ptr.valid_range_mut() =
|
*data_ptr.valid_range_mut() =
|
||||||
|
@ -9,7 +9,6 @@ note: ...which requires type-checking `make_dyn_star`...
|
|||||||
|
|
|
|
||||||
LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a {
|
LL | fn make_dyn_star<'a, T: PointerLike + Debug + 'a>(t: T) -> impl PointerLike + Debug + 'a {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
= note: ...which requires computing layout of `make_dyn_star::{opaque#0}`...
|
|
||||||
= note: ...which requires computing layout (naive) of `make_dyn_star::{opaque#0}`...
|
= note: ...which requires computing layout (naive) of `make_dyn_star::{opaque#0}`...
|
||||||
= note: ...which requires normalizing `make_dyn_star::{opaque#0}`...
|
= note: ...which requires normalizing `make_dyn_star::{opaque#0}`...
|
||||||
= note: ...which again requires computing type of `make_dyn_star::{opaque#0}`, completing the cycle
|
= note: ...which again requires computing type of `make_dyn_star::{opaque#0}`, completing the cycle
|
||||||
|
Loading…
Reference in New Issue
Block a user