Skip to content

Commit c45dda9

Browse files
committed
rustc_target: move for_variant and field TyLayout methods to a trait.
1 parent 7a51476 commit c45dda9

File tree

2 files changed

+98
-81
lines changed

2 files changed

+98
-81
lines changed

src/librustc/ty/layout.rs

+39-80
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use std::cmp;
1919
use std::fmt;
2020
use std::i128;
2121
use std::mem;
22-
use std::ops::{Deref, RangeInclusive};
22+
use std::ops::RangeInclusive;
2323

2424
use ich::StableHashingContext;
2525
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
@@ -801,9 +801,9 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
801801

802802
if let Some(i) = dataful_variant {
803803
let count = (niche_variants.end - niche_variants.start + 1) as u128;
804-
for (field_index, field) in variants[i].iter().enumerate() {
804+
for (field_index, &field) in variants[i].iter().enumerate() {
805805
let (offset, niche, niche_start) =
806-
match field.find_niche(self, count)? {
806+
match self.find_niche(field, count)? {
807807
Some(niche) => niche,
808808
None => continue
809809
};
@@ -1300,26 +1300,6 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> {
13001300
}
13011301
}
13021302

1303-
/// The details of the layout of a type, alongside the type itself.
1304-
/// Provides various type traversal APIs (e.g. recursing into fields).
1305-
///
1306-
/// Note that the details are NOT guaranteed to always be identical
1307-
/// to those obtained from `layout_of(ty)`, as we need to produce
1308-
/// layouts for which Rust types do not exist, such as enum variants
1309-
/// or synthetic fields of enums (i.e. discriminants) and fat pointers.
1310-
#[derive(Copy, Clone, Debug)]
1311-
pub struct TyLayout<'tcx> {
1312-
pub ty: Ty<'tcx>,
1313-
details: &'tcx LayoutDetails
1314-
}
1315-
1316-
impl<'tcx> Deref for TyLayout<'tcx> {
1317-
type Target = &'tcx LayoutDetails;
1318-
fn deref(&self) -> &&'tcx LayoutDetails {
1319-
&self.details
1320-
}
1321-
}
1322-
13231303
pub trait HasTyCtxt<'tcx>: HasDataLayout {
13241304
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
13251305
}
@@ -1371,6 +1351,8 @@ impl<T, E> MaybeResult<T> for Result<T, E> {
13711351
}
13721352
}
13731353

1354+
pub type TyLayout<'tcx> = ::rustc_target::abi::TyLayout<'tcx, Ty<'tcx>>;
1355+
13741356
impl<'a, 'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
13751357
type Ty = Ty<'tcx>;
13761358
type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
@@ -1458,22 +1440,22 @@ impl<'a, 'tcx> ty::maps::TyCtxtAt<'a, 'tcx, 'tcx> {
14581440
}
14591441
}
14601442

1461-
impl<'a, 'tcx> TyLayout<'tcx> {
1462-
pub fn for_variant<C>(&self, cx: C, variant_index: usize) -> Self
1463-
where C: LayoutOf<Ty = Ty<'tcx>> + HasTyCtxt<'tcx>,
1464-
C::TyLayout: MaybeResult<TyLayout<'tcx>>
1465-
{
1466-
let details = match self.variants {
1467-
Variants::Single { index } if index == variant_index => self.details,
1443+
impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
1444+
where C: LayoutOf<Ty = Ty<'tcx>> + HasTyCtxt<'tcx>,
1445+
C::TyLayout: MaybeResult<TyLayout<'tcx>>
1446+
{
1447+
fn for_variant(this: TyLayout<'tcx>, cx: C, variant_index: usize) -> TyLayout<'tcx> {
1448+
let details = match this.variants {
1449+
Variants::Single { index } if index == variant_index => this.details,
14681450

14691451
Variants::Single { index } => {
14701452
// Deny calling for_variant more than once for non-Single enums.
1471-
cx.layout_of(self.ty).map_same(|layout| {
1453+
cx.layout_of(this.ty).map_same(|layout| {
14721454
assert_eq!(layout.variants, Variants::Single { index });
14731455
layout
14741456
});
14751457

1476-
let fields = match self.ty.sty {
1458+
let fields = match this.ty.sty {
14771459
ty::TyAdt(def, _) => def.variants[variant_index].fields.len(),
14781460
_ => bug!()
14791461
};
@@ -1491,17 +1473,14 @@ impl<'a, 'tcx> TyLayout<'tcx> {
14911473
assert_eq!(details.variants, Variants::Single { index: variant_index });
14921474

14931475
TyLayout {
1494-
ty: self.ty,
1476+
ty: this.ty,
14951477
details
14961478
}
14971479
}
14981480

1499-
pub fn field<C>(&self, cx: C, i: usize) -> C::TyLayout
1500-
where C: LayoutOf<Ty = Ty<'tcx>> + HasTyCtxt<'tcx>,
1501-
C::TyLayout: MaybeResult<TyLayout<'tcx>>
1502-
{
1481+
fn field(this: TyLayout<'tcx>, cx: C, i: usize) -> C::TyLayout {
15031482
let tcx = cx.tcx();
1504-
cx.layout_of(match self.ty.sty {
1483+
cx.layout_of(match this.ty.sty {
15051484
ty::TyBool |
15061485
ty::TyChar |
15071486
ty::TyInt(_) |
@@ -1513,7 +1492,7 @@ impl<'a, 'tcx> TyLayout<'tcx> {
15131492
ty::TyGeneratorWitness(..) |
15141493
ty::TyForeign(..) |
15151494
ty::TyDynamic(..) => {
1516-
bug!("TyLayout::field_type({:?}): not applicable", self)
1495+
bug!("TyLayout::field_type({:?}): not applicable", this)
15171496
}
15181497

15191498
// Potentially-fat pointers.
@@ -1527,13 +1506,13 @@ impl<'a, 'tcx> TyLayout<'tcx> {
15271506
// as the `Abi` or `FieldPlacement` is checked by users.
15281507
if i == 0 {
15291508
let nil = tcx.mk_nil();
1530-
let ptr_ty = if self.ty.is_unsafe_ptr() {
1509+
let ptr_ty = if this.ty.is_unsafe_ptr() {
15311510
tcx.mk_mut_ptr(nil)
15321511
} else {
15331512
tcx.mk_mut_ref(tcx.types.re_static, nil)
15341513
};
15351514
return cx.layout_of(ptr_ty).map_same(|mut ptr_layout| {
1536-
ptr_layout.ty = self.ty;
1515+
ptr_layout.ty = this.ty;
15371516
ptr_layout
15381517
});
15391518
}
@@ -1546,7 +1525,7 @@ impl<'a, 'tcx> TyLayout<'tcx> {
15461525
// the correct number of vtables slots.
15471526
tcx.mk_imm_ref(tcx.types.re_static, tcx.mk_nil())
15481527
}
1549-
_ => bug!("TyLayout::field_type({:?}): not applicable", self)
1528+
_ => bug!("TyLayout::field_type({:?}): not applicable", this)
15501529
}
15511530
}
15521531

@@ -1568,12 +1547,12 @@ impl<'a, 'tcx> TyLayout<'tcx> {
15681547

15691548
// SIMD vector types.
15701549
ty::TyAdt(def, ..) if def.repr.simd() => {
1571-
self.ty.simd_type(tcx)
1550+
this.ty.simd_type(tcx)
15721551
}
15731552

15741553
// ADTs.
15751554
ty::TyAdt(def, substs) => {
1576-
match self.variants {
1555+
match this.variants {
15771556
Variants::Single { index } => {
15781557
def.variants[index].fields[i].ty(tcx, substs)
15791558
}
@@ -1593,45 +1572,25 @@ impl<'a, 'tcx> TyLayout<'tcx> {
15931572

15941573
ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) |
15951574
ty::TyInfer(_) | ty::TyError => {
1596-
bug!("TyLayout::field_type: unexpected type `{}`", self.ty)
1575+
bug!("TyLayout::field_type: unexpected type `{}`", this.ty)
15971576
}
15981577
})
15991578
}
1579+
}
16001580

1601-
/// Returns true if the layout corresponds to an unsized type.
1602-
pub fn is_unsized(&self) -> bool {
1603-
self.abi.is_unsized()
1604-
}
1605-
1606-
/// Returns true if the type is a ZST and not unsized.
1607-
pub fn is_zst(&self) -> bool {
1608-
match self.abi {
1609-
Abi::Uninhabited => true,
1610-
Abi::Scalar(_) |
1611-
Abi::ScalarPair(..) |
1612-
Abi::Vector { .. } => false,
1613-
Abi::Aggregate { sized } => sized && self.size.bytes() == 0
1614-
}
1615-
}
1616-
1617-
pub fn size_and_align(&self) -> (Size, Align) {
1618-
(self.size, self.align)
1619-
}
1620-
1581+
impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
16211582
/// Find the offset of a niche leaf field, starting from
16221583
/// the given type and recursing through aggregates, which
16231584
/// has at least `count` consecutive invalid values.
16241585
/// The tuple is `(offset, scalar, niche_value)`.
16251586
// FIXME(eddyb) traverse already optimized enums.
1626-
fn find_niche<C>(&self, cx: C, count: u128)
1587+
fn find_niche(self, layout: TyLayout<'tcx>, count: u128)
16271588
-> Result<Option<(Size, Scalar, u128)>, LayoutError<'tcx>>
1628-
where C: LayoutOf<Ty = Ty<'tcx>, TyLayout = Result<Self, LayoutError<'tcx>>> +
1629-
HasTyCtxt<'tcx>
16301589
{
16311590
let scalar_component = |scalar: &Scalar, offset| {
16321591
let Scalar { value, valid_range: ref v } = *scalar;
16331592

1634-
let bits = value.size(cx).bits();
1593+
let bits = value.size(self).bits();
16351594
assert!(bits <= 128);
16361595
let max_value = !0u128 >> (128 - bits);
16371596

@@ -1658,17 +1617,17 @@ impl<'a, 'tcx> TyLayout<'tcx> {
16581617
// Locals variables which live across yields are stored
16591618
// in the generator type as fields. These may be uninitialized
16601619
// so we don't look for niches there.
1661-
if let ty::TyGenerator(..) = self.ty.sty {
1620+
if let ty::TyGenerator(..) = layout.ty.sty {
16621621
return Ok(None);
16631622
}
16641623

1665-
match self.abi {
1624+
match layout.abi {
16661625
Abi::Scalar(ref scalar) => {
16671626
return Ok(scalar_component(scalar, Size::from_bytes(0)));
16681627
}
16691628
Abi::ScalarPair(ref a, ref b) => {
16701629
return Ok(scalar_component(a, Size::from_bytes(0)).or_else(|| {
1671-
scalar_component(b, a.value.size(cx).abi_align(b.value.align(cx)))
1630+
scalar_component(b, a.value.size(self).abi_align(b.value.align(self)))
16721631
}));
16731632
}
16741633
Abi::Vector { ref element, .. } => {
@@ -1678,22 +1637,22 @@ impl<'a, 'tcx> TyLayout<'tcx> {
16781637
}
16791638

16801639
// Perhaps one of the fields is non-zero, let's recurse and find out.
1681-
if let FieldPlacement::Union(_) = self.fields {
1640+
if let FieldPlacement::Union(_) = layout.fields {
16821641
// Only Rust enums have safe-to-inspect fields
16831642
// (a discriminant), other unions are unsafe.
1684-
if let Variants::Single { .. } = self.variants {
1643+
if let Variants::Single { .. } = layout.variants {
16851644
return Ok(None);
16861645
}
16871646
}
1688-
if let FieldPlacement::Array { .. } = self.fields {
1689-
if self.fields.count() > 0 {
1690-
return self.field(cx, 0)?.find_niche(cx, count);
1647+
if let FieldPlacement::Array { .. } = layout.fields {
1648+
if layout.fields.count() > 0 {
1649+
return self.find_niche(layout.field(self, 0)?, count);
16911650
}
16921651
}
1693-
for i in 0..self.fields.count() {
1694-
let r = self.field(cx, i)?.find_niche(cx, count)?;
1652+
for i in 0..layout.fields.count() {
1653+
let r = self.find_niche(layout.field(self, i)?, count)?;
16951654
if let Some((offset, scalar, niche_value)) = r {
1696-
let offset = self.fields.offset(i) + offset;
1655+
let offset = layout.fields.offset(i) + offset;
16971656
return Ok(Some((offset, scalar, niche_value)));
16981657
}
16991658
}

src/librustc_target/abi/mod.rs

+59-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub use self::Primitive::*;
1414
use spec::Target;
1515

1616
use std::cmp;
17-
use std::ops::{Add, Sub, Mul, AddAssign, RangeInclusive};
17+
use std::ops::{Add, Deref, Sub, Mul, AddAssign, RangeInclusive};
1818

1919
pub mod call;
2020

@@ -757,9 +757,67 @@ impl LayoutDetails {
757757
}
758758
}
759759

760+
/// The details of the layout of a type, alongside the type itself.
761+
/// Provides various type traversal APIs (e.g. recursing into fields).
762+
///
763+
/// Note that the details are NOT guaranteed to always be identical
764+
/// to those obtained from `layout_of(ty)`, as we need to produce
765+
/// layouts for which Rust types do not exist, such as enum variants
766+
/// or synthetic fields of enums (i.e. discriminants) and fat pointers.
767+
#[derive(Copy, Clone, Debug)]
768+
pub struct TyLayout<'a, Ty> {
769+
pub ty: Ty,
770+
pub details: &'a LayoutDetails
771+
}
772+
773+
impl<'a, Ty> Deref for TyLayout<'a, Ty> {
774+
type Target = &'a LayoutDetails;
775+
fn deref(&self) -> &&'a LayoutDetails {
776+
&self.details
777+
}
778+
}
779+
760780
pub trait LayoutOf {
761781
type Ty;
762782
type TyLayout;
763783

764784
fn layout_of(self, ty: Self::Ty) -> Self::TyLayout;
765785
}
786+
787+
pub trait TyLayoutMethods<'a, C: LayoutOf>: Sized {
788+
fn for_variant(this: TyLayout<'a, Self>, cx: C, variant_index: usize) -> TyLayout<'a, Self>;
789+
fn field(this: TyLayout<'a, Self>, cx: C, i: usize) -> C::TyLayout;
790+
}
791+
792+
impl<'a, Ty> TyLayout<'a, Ty> {
793+
pub fn for_variant<C>(self, cx: C, variant_index: usize) -> Self
794+
where Ty: TyLayoutMethods<'a, C>, C: LayoutOf {
795+
Ty::for_variant(self, cx, variant_index)
796+
}
797+
pub fn field<C>(self, cx: C, i: usize) -> C::TyLayout
798+
where Ty: TyLayoutMethods<'a, C>, C: LayoutOf {
799+
Ty::field(self, cx, i)
800+
}
801+
}
802+
803+
impl<'a, Ty> TyLayout<'a, Ty> {
804+
/// Returns true if the layout corresponds to an unsized type.
805+
pub fn is_unsized(&self) -> bool {
806+
self.abi.is_unsized()
807+
}
808+
809+
/// Returns true if the type is a ZST and not unsized.
810+
pub fn is_zst(&self) -> bool {
811+
match self.abi {
812+
Abi::Uninhabited => true,
813+
Abi::Scalar(_) |
814+
Abi::ScalarPair(..) |
815+
Abi::Vector { .. } => false,
816+
Abi::Aggregate { sized } => sized && self.size.bytes() == 0
817+
}
818+
}
819+
820+
pub fn size_and_align(&self) -> (Size, Align) {
821+
(self.size, self.align)
822+
}
823+
}

0 commit comments

Comments
 (0)