rustc_target: move for_variant and field TyLayout methods to a trait.
This commit is contained in:
parent
7a5147616b
commit
c45dda92fe
2 changed files with 98 additions and 81 deletions
|
@ -19,7 +19,7 @@ use std::cmp;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::i128;
|
use std::i128;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{Deref, RangeInclusive};
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
use ich::StableHashingContext;
|
use ich::StableHashingContext;
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
|
||||||
|
@ -801,9 +801,9 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
|
||||||
|
|
||||||
if let Some(i) = dataful_variant {
|
if let Some(i) = dataful_variant {
|
||||||
let count = (niche_variants.end - niche_variants.start + 1) as u128;
|
let count = (niche_variants.end - niche_variants.start + 1) as u128;
|
||||||
for (field_index, field) in variants[i].iter().enumerate() {
|
for (field_index, &field) in variants[i].iter().enumerate() {
|
||||||
let (offset, niche, niche_start) =
|
let (offset, niche, niche_start) =
|
||||||
match field.find_niche(self, count)? {
|
match self.find_niche(field, count)? {
|
||||||
Some(niche) => niche,
|
Some(niche) => niche,
|
||||||
None => continue
|
None => continue
|
||||||
};
|
};
|
||||||
|
@ -1300,26 +1300,6 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The details of the layout of a type, alongside the type itself.
|
|
||||||
/// Provides various type traversal APIs (e.g. recursing into fields).
|
|
||||||
///
|
|
||||||
/// Note that the details are NOT guaranteed to always be identical
|
|
||||||
/// to those obtained from `layout_of(ty)`, as we need to produce
|
|
||||||
/// layouts for which Rust types do not exist, such as enum variants
|
|
||||||
/// or synthetic fields of enums (i.e. discriminants) and fat pointers.
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub struct TyLayout<'tcx> {
|
|
||||||
pub ty: Ty<'tcx>,
|
|
||||||
details: &'tcx LayoutDetails
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Deref for TyLayout<'tcx> {
|
|
||||||
type Target = &'tcx LayoutDetails;
|
|
||||||
fn deref(&self) -> &&'tcx LayoutDetails {
|
|
||||||
&self.details
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait HasTyCtxt<'tcx>: HasDataLayout {
|
pub trait HasTyCtxt<'tcx>: HasDataLayout {
|
||||||
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
|
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
|
||||||
}
|
}
|
||||||
|
@ -1371,6 +1351,8 @@ impl<T, E> MaybeResult<T> for Result<T, E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type TyLayout<'tcx> = ::rustc_target::abi::TyLayout<'tcx, Ty<'tcx>>;
|
||||||
|
|
||||||
impl<'a, 'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
|
impl<'a, 'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
|
||||||
type Ty = Ty<'tcx>;
|
type Ty = Ty<'tcx>;
|
||||||
type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
|
type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
|
||||||
|
@ -1458,22 +1440,22 @@ impl<'a, 'tcx> ty::maps::TyCtxtAt<'a, 'tcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> TyLayout<'tcx> {
|
impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
|
||||||
pub fn for_variant<C>(&self, cx: C, variant_index: usize) -> Self
|
where C: LayoutOf<Ty = Ty<'tcx>> + HasTyCtxt<'tcx>,
|
||||||
where C: LayoutOf<Ty = Ty<'tcx>> + HasTyCtxt<'tcx>,
|
C::TyLayout: MaybeResult<TyLayout<'tcx>>
|
||||||
C::TyLayout: MaybeResult<TyLayout<'tcx>>
|
{
|
||||||
{
|
fn for_variant(this: TyLayout<'tcx>, cx: C, variant_index: usize) -> TyLayout<'tcx> {
|
||||||
let details = match self.variants {
|
let details = match this.variants {
|
||||||
Variants::Single { index } if index == variant_index => self.details,
|
Variants::Single { index } if index == variant_index => this.details,
|
||||||
|
|
||||||
Variants::Single { index } => {
|
Variants::Single { index } => {
|
||||||
// Deny calling for_variant more than once for non-Single enums.
|
// Deny calling for_variant more than once for non-Single enums.
|
||||||
cx.layout_of(self.ty).map_same(|layout| {
|
cx.layout_of(this.ty).map_same(|layout| {
|
||||||
assert_eq!(layout.variants, Variants::Single { index });
|
assert_eq!(layout.variants, Variants::Single { index });
|
||||||
layout
|
layout
|
||||||
});
|
});
|
||||||
|
|
||||||
let fields = match self.ty.sty {
|
let fields = match this.ty.sty {
|
||||||
ty::TyAdt(def, _) => def.variants[variant_index].fields.len(),
|
ty::TyAdt(def, _) => def.variants[variant_index].fields.len(),
|
||||||
_ => bug!()
|
_ => bug!()
|
||||||
};
|
};
|
||||||
|
@ -1491,17 +1473,14 @@ impl<'a, 'tcx> TyLayout<'tcx> {
|
||||||
assert_eq!(details.variants, Variants::Single { index: variant_index });
|
assert_eq!(details.variants, Variants::Single { index: variant_index });
|
||||||
|
|
||||||
TyLayout {
|
TyLayout {
|
||||||
ty: self.ty,
|
ty: this.ty,
|
||||||
details
|
details
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn field<C>(&self, cx: C, i: usize) -> C::TyLayout
|
fn field(this: TyLayout<'tcx>, cx: C, i: usize) -> C::TyLayout {
|
||||||
where C: LayoutOf<Ty = Ty<'tcx>> + HasTyCtxt<'tcx>,
|
|
||||||
C::TyLayout: MaybeResult<TyLayout<'tcx>>
|
|
||||||
{
|
|
||||||
let tcx = cx.tcx();
|
let tcx = cx.tcx();
|
||||||
cx.layout_of(match self.ty.sty {
|
cx.layout_of(match this.ty.sty {
|
||||||
ty::TyBool |
|
ty::TyBool |
|
||||||
ty::TyChar |
|
ty::TyChar |
|
||||||
ty::TyInt(_) |
|
ty::TyInt(_) |
|
||||||
|
@ -1513,7 +1492,7 @@ impl<'a, 'tcx> TyLayout<'tcx> {
|
||||||
ty::TyGeneratorWitness(..) |
|
ty::TyGeneratorWitness(..) |
|
||||||
ty::TyForeign(..) |
|
ty::TyForeign(..) |
|
||||||
ty::TyDynamic(..) => {
|
ty::TyDynamic(..) => {
|
||||||
bug!("TyLayout::field_type({:?}): not applicable", self)
|
bug!("TyLayout::field_type({:?}): not applicable", this)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Potentially-fat pointers.
|
// Potentially-fat pointers.
|
||||||
|
@ -1527,13 +1506,13 @@ impl<'a, 'tcx> TyLayout<'tcx> {
|
||||||
// as the `Abi` or `FieldPlacement` is checked by users.
|
// as the `Abi` or `FieldPlacement` is checked by users.
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
let nil = tcx.mk_nil();
|
let nil = tcx.mk_nil();
|
||||||
let ptr_ty = if self.ty.is_unsafe_ptr() {
|
let ptr_ty = if this.ty.is_unsafe_ptr() {
|
||||||
tcx.mk_mut_ptr(nil)
|
tcx.mk_mut_ptr(nil)
|
||||||
} else {
|
} else {
|
||||||
tcx.mk_mut_ref(tcx.types.re_static, nil)
|
tcx.mk_mut_ref(tcx.types.re_static, nil)
|
||||||
};
|
};
|
||||||
return cx.layout_of(ptr_ty).map_same(|mut ptr_layout| {
|
return cx.layout_of(ptr_ty).map_same(|mut ptr_layout| {
|
||||||
ptr_layout.ty = self.ty;
|
ptr_layout.ty = this.ty;
|
||||||
ptr_layout
|
ptr_layout
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1546,7 +1525,7 @@ impl<'a, 'tcx> TyLayout<'tcx> {
|
||||||
// the correct number of vtables slots.
|
// the correct number of vtables slots.
|
||||||
tcx.mk_imm_ref(tcx.types.re_static, tcx.mk_nil())
|
tcx.mk_imm_ref(tcx.types.re_static, tcx.mk_nil())
|
||||||
}
|
}
|
||||||
_ => bug!("TyLayout::field_type({:?}): not applicable", self)
|
_ => bug!("TyLayout::field_type({:?}): not applicable", this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1568,12 +1547,12 @@ impl<'a, 'tcx> TyLayout<'tcx> {
|
||||||
|
|
||||||
// SIMD vector types.
|
// SIMD vector types.
|
||||||
ty::TyAdt(def, ..) if def.repr.simd() => {
|
ty::TyAdt(def, ..) if def.repr.simd() => {
|
||||||
self.ty.simd_type(tcx)
|
this.ty.simd_type(tcx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ADTs.
|
// ADTs.
|
||||||
ty::TyAdt(def, substs) => {
|
ty::TyAdt(def, substs) => {
|
||||||
match self.variants {
|
match this.variants {
|
||||||
Variants::Single { index } => {
|
Variants::Single { index } => {
|
||||||
def.variants[index].fields[i].ty(tcx, substs)
|
def.variants[index].fields[i].ty(tcx, substs)
|
||||||
}
|
}
|
||||||
|
@ -1593,45 +1572,25 @@ impl<'a, 'tcx> TyLayout<'tcx> {
|
||||||
|
|
||||||
ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) |
|
ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) |
|
||||||
ty::TyInfer(_) | ty::TyError => {
|
ty::TyInfer(_) | ty::TyError => {
|
||||||
bug!("TyLayout::field_type: unexpected type `{}`", self.ty)
|
bug!("TyLayout::field_type: unexpected type `{}`", this.ty)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if the layout corresponds to an unsized type.
|
impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
|
||||||
pub fn is_unsized(&self) -> bool {
|
|
||||||
self.abi.is_unsized()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the type is a ZST and not unsized.
|
|
||||||
pub fn is_zst(&self) -> bool {
|
|
||||||
match self.abi {
|
|
||||||
Abi::Uninhabited => true,
|
|
||||||
Abi::Scalar(_) |
|
|
||||||
Abi::ScalarPair(..) |
|
|
||||||
Abi::Vector { .. } => false,
|
|
||||||
Abi::Aggregate { sized } => sized && self.size.bytes() == 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn size_and_align(&self) -> (Size, Align) {
|
|
||||||
(self.size, self.align)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find the offset of a niche leaf field, starting from
|
/// Find the offset of a niche leaf field, starting from
|
||||||
/// the given type and recursing through aggregates, which
|
/// the given type and recursing through aggregates, which
|
||||||
/// has at least `count` consecutive invalid values.
|
/// has at least `count` consecutive invalid values.
|
||||||
/// The tuple is `(offset, scalar, niche_value)`.
|
/// The tuple is `(offset, scalar, niche_value)`.
|
||||||
// FIXME(eddyb) traverse already optimized enums.
|
// FIXME(eddyb) traverse already optimized enums.
|
||||||
fn find_niche<C>(&self, cx: C, count: u128)
|
fn find_niche(self, layout: TyLayout<'tcx>, count: u128)
|
||||||
-> Result<Option<(Size, Scalar, u128)>, LayoutError<'tcx>>
|
-> Result<Option<(Size, Scalar, u128)>, LayoutError<'tcx>>
|
||||||
where C: LayoutOf<Ty = Ty<'tcx>, TyLayout = Result<Self, LayoutError<'tcx>>> +
|
|
||||||
HasTyCtxt<'tcx>
|
|
||||||
{
|
{
|
||||||
let scalar_component = |scalar: &Scalar, offset| {
|
let scalar_component = |scalar: &Scalar, offset| {
|
||||||
let Scalar { value, valid_range: ref v } = *scalar;
|
let Scalar { value, valid_range: ref v } = *scalar;
|
||||||
|
|
||||||
let bits = value.size(cx).bits();
|
let bits = value.size(self).bits();
|
||||||
assert!(bits <= 128);
|
assert!(bits <= 128);
|
||||||
let max_value = !0u128 >> (128 - bits);
|
let max_value = !0u128 >> (128 - bits);
|
||||||
|
|
||||||
|
@ -1658,17 +1617,17 @@ impl<'a, 'tcx> TyLayout<'tcx> {
|
||||||
// Locals variables which live across yields are stored
|
// Locals variables which live across yields are stored
|
||||||
// in the generator type as fields. These may be uninitialized
|
// in the generator type as fields. These may be uninitialized
|
||||||
// so we don't look for niches there.
|
// so we don't look for niches there.
|
||||||
if let ty::TyGenerator(..) = self.ty.sty {
|
if let ty::TyGenerator(..) = layout.ty.sty {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.abi {
|
match layout.abi {
|
||||||
Abi::Scalar(ref scalar) => {
|
Abi::Scalar(ref scalar) => {
|
||||||
return Ok(scalar_component(scalar, Size::from_bytes(0)));
|
return Ok(scalar_component(scalar, Size::from_bytes(0)));
|
||||||
}
|
}
|
||||||
Abi::ScalarPair(ref a, ref b) => {
|
Abi::ScalarPair(ref a, ref b) => {
|
||||||
return Ok(scalar_component(a, Size::from_bytes(0)).or_else(|| {
|
return Ok(scalar_component(a, Size::from_bytes(0)).or_else(|| {
|
||||||
scalar_component(b, a.value.size(cx).abi_align(b.value.align(cx)))
|
scalar_component(b, a.value.size(self).abi_align(b.value.align(self)))
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
Abi::Vector { ref element, .. } => {
|
Abi::Vector { ref element, .. } => {
|
||||||
|
@ -1678,22 +1637,22 @@ impl<'a, 'tcx> TyLayout<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perhaps one of the fields is non-zero, let's recurse and find out.
|
// Perhaps one of the fields is non-zero, let's recurse and find out.
|
||||||
if let FieldPlacement::Union(_) = self.fields {
|
if let FieldPlacement::Union(_) = layout.fields {
|
||||||
// Only Rust enums have safe-to-inspect fields
|
// Only Rust enums have safe-to-inspect fields
|
||||||
// (a discriminant), other unions are unsafe.
|
// (a discriminant), other unions are unsafe.
|
||||||
if let Variants::Single { .. } = self.variants {
|
if let Variants::Single { .. } = layout.variants {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let FieldPlacement::Array { .. } = self.fields {
|
if let FieldPlacement::Array { .. } = layout.fields {
|
||||||
if self.fields.count() > 0 {
|
if layout.fields.count() > 0 {
|
||||||
return self.field(cx, 0)?.find_niche(cx, count);
|
return self.find_niche(layout.field(self, 0)?, count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i in 0..self.fields.count() {
|
for i in 0..layout.fields.count() {
|
||||||
let r = self.field(cx, i)?.find_niche(cx, count)?;
|
let r = self.find_niche(layout.field(self, i)?, count)?;
|
||||||
if let Some((offset, scalar, niche_value)) = r {
|
if let Some((offset, scalar, niche_value)) = r {
|
||||||
let offset = self.fields.offset(i) + offset;
|
let offset = layout.fields.offset(i) + offset;
|
||||||
return Ok(Some((offset, scalar, niche_value)));
|
return Ok(Some((offset, scalar, niche_value)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ pub use self::Primitive::*;
|
||||||
use spec::Target;
|
use spec::Target;
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::ops::{Add, Sub, Mul, AddAssign, RangeInclusive};
|
use std::ops::{Add, Deref, Sub, Mul, AddAssign, RangeInclusive};
|
||||||
|
|
||||||
pub mod call;
|
pub mod call;
|
||||||
|
|
||||||
|
@ -757,9 +757,67 @@ impl LayoutDetails {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The details of the layout of a type, alongside the type itself.
|
||||||
|
/// Provides various type traversal APIs (e.g. recursing into fields).
|
||||||
|
///
|
||||||
|
/// Note that the details are NOT guaranteed to always be identical
|
||||||
|
/// to those obtained from `layout_of(ty)`, as we need to produce
|
||||||
|
/// layouts for which Rust types do not exist, such as enum variants
|
||||||
|
/// or synthetic fields of enums (i.e. discriminants) and fat pointers.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct TyLayout<'a, Ty> {
|
||||||
|
pub ty: Ty,
|
||||||
|
pub details: &'a LayoutDetails
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Ty> Deref for TyLayout<'a, Ty> {
|
||||||
|
type Target = &'a LayoutDetails;
|
||||||
|
fn deref(&self) -> &&'a LayoutDetails {
|
||||||
|
&self.details
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait LayoutOf {
|
pub trait LayoutOf {
|
||||||
type Ty;
|
type Ty;
|
||||||
type TyLayout;
|
type TyLayout;
|
||||||
|
|
||||||
fn layout_of(self, ty: Self::Ty) -> Self::TyLayout;
|
fn layout_of(self, ty: Self::Ty) -> Self::TyLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait TyLayoutMethods<'a, C: LayoutOf>: Sized {
|
||||||
|
fn for_variant(this: TyLayout<'a, Self>, cx: C, variant_index: usize) -> TyLayout<'a, Self>;
|
||||||
|
fn field(this: TyLayout<'a, Self>, cx: C, i: usize) -> C::TyLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Ty> TyLayout<'a, Ty> {
|
||||||
|
pub fn for_variant<C>(self, cx: C, variant_index: usize) -> Self
|
||||||
|
where Ty: TyLayoutMethods<'a, C>, C: LayoutOf {
|
||||||
|
Ty::for_variant(self, cx, variant_index)
|
||||||
|
}
|
||||||
|
pub fn field<C>(self, cx: C, i: usize) -> C::TyLayout
|
||||||
|
where Ty: TyLayoutMethods<'a, C>, C: LayoutOf {
|
||||||
|
Ty::field(self, cx, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Ty> TyLayout<'a, Ty> {
|
||||||
|
/// Returns true if the layout corresponds to an unsized type.
|
||||||
|
pub fn is_unsized(&self) -> bool {
|
||||||
|
self.abi.is_unsized()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the type is a ZST and not unsized.
|
||||||
|
pub fn is_zst(&self) -> bool {
|
||||||
|
match self.abi {
|
||||||
|
Abi::Uninhabited => true,
|
||||||
|
Abi::Scalar(_) |
|
||||||
|
Abi::ScalarPair(..) |
|
||||||
|
Abi::Vector { .. } => false,
|
||||||
|
Abi::Aggregate { sized } => sized && self.size.bytes() == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size_and_align(&self) -> (Size, Align) {
|
||||||
|
(self.size, self.align)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue