From c45dda92feedaaed22bd9d74ec24164dc206da44 Mon Sep 17 00:00:00 2001 From: Irina Popa Date: Wed, 7 Feb 2018 19:27:43 +0200 Subject: [PATCH] rustc_target: move for_variant and field TyLayout methods to a trait. --- src/librustc/ty/layout.rs | 119 +++++++++++---------------------- src/librustc_target/abi/mod.rs | 60 ++++++++++++++++- 2 files changed, 98 insertions(+), 81 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 069250bb055..f7ac25a0db0 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -19,7 +19,7 @@ use std::cmp; use std::fmt; use std::i128; use std::mem; -use std::ops::{Deref, RangeInclusive}; +use std::ops::RangeInclusive; use ich::StableHashingContext; 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 { 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) = - match field.find_niche(self, count)? { + match self.find_niche(field, count)? { Some(niche) => niche, 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 { fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>; } @@ -1371,6 +1351,8 @@ impl MaybeResult for Result { } } +pub type TyLayout<'tcx> = ::rustc_target::abi::TyLayout<'tcx, Ty<'tcx>>; + impl<'a, 'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { type Ty = Ty<'tcx>; type TyLayout = Result, LayoutError<'tcx>>; @@ -1458,22 +1440,22 @@ impl<'a, 'tcx> ty::maps::TyCtxtAt<'a, 'tcx, 'tcx> { } } -impl<'a, 'tcx> TyLayout<'tcx> { - pub fn for_variant(&self, cx: C, variant_index: usize) -> Self - where C: LayoutOf> + HasTyCtxt<'tcx>, - C::TyLayout: MaybeResult> - { - let details = match self.variants { - Variants::Single { index } if index == variant_index => self.details, +impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> + where C: LayoutOf> + HasTyCtxt<'tcx>, + C::TyLayout: MaybeResult> +{ + fn for_variant(this: TyLayout<'tcx>, cx: C, variant_index: usize) -> TyLayout<'tcx> { + let details = match this.variants { + Variants::Single { index } if index == variant_index => this.details, Variants::Single { index } => { // 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 }); layout }); - let fields = match self.ty.sty { + let fields = match this.ty.sty { ty::TyAdt(def, _) => def.variants[variant_index].fields.len(), _ => bug!() }; @@ -1491,17 +1473,14 @@ impl<'a, 'tcx> TyLayout<'tcx> { assert_eq!(details.variants, Variants::Single { index: variant_index }); TyLayout { - ty: self.ty, + ty: this.ty, details } } - pub fn field(&self, cx: C, i: usize) -> C::TyLayout - where C: LayoutOf> + HasTyCtxt<'tcx>, - C::TyLayout: MaybeResult> - { + fn field(this: TyLayout<'tcx>, cx: C, i: usize) -> C::TyLayout { let tcx = cx.tcx(); - cx.layout_of(match self.ty.sty { + cx.layout_of(match this.ty.sty { ty::TyBool | ty::TyChar | ty::TyInt(_) | @@ -1513,7 +1492,7 @@ impl<'a, 'tcx> TyLayout<'tcx> { ty::TyGeneratorWitness(..) | ty::TyForeign(..) | ty::TyDynamic(..) => { - bug!("TyLayout::field_type({:?}): not applicable", self) + bug!("TyLayout::field_type({:?}): not applicable", this) } // Potentially-fat pointers. @@ -1527,13 +1506,13 @@ impl<'a, 'tcx> TyLayout<'tcx> { // as the `Abi` or `FieldPlacement` is checked by users. if i == 0 { 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) } else { tcx.mk_mut_ref(tcx.types.re_static, nil) }; return cx.layout_of(ptr_ty).map_same(|mut ptr_layout| { - ptr_layout.ty = self.ty; + ptr_layout.ty = this.ty; ptr_layout }); } @@ -1546,7 +1525,7 @@ impl<'a, 'tcx> TyLayout<'tcx> { // the correct number of vtables slots. 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. ty::TyAdt(def, ..) if def.repr.simd() => { - self.ty.simd_type(tcx) + this.ty.simd_type(tcx) } // ADTs. ty::TyAdt(def, substs) => { - match self.variants { + match this.variants { Variants::Single { index } => { def.variants[index].fields[i].ty(tcx, substs) } @@ -1593,45 +1572,25 @@ impl<'a, 'tcx> TyLayout<'tcx> { ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) | 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. - 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) - } - +impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { /// Find the offset of a niche leaf field, starting from /// the given type and recursing through aggregates, which /// has at least `count` consecutive invalid values. /// The tuple is `(offset, scalar, niche_value)`. // FIXME(eddyb) traverse already optimized enums. - fn find_niche(&self, cx: C, count: u128) + fn find_niche(self, layout: TyLayout<'tcx>, count: u128) -> Result, LayoutError<'tcx>> - where C: LayoutOf, TyLayout = Result>> + - HasTyCtxt<'tcx> { let scalar_component = |scalar: &Scalar, offset| { let Scalar { value, valid_range: ref v } = *scalar; - let bits = value.size(cx).bits(); + let bits = value.size(self).bits(); assert!(bits <= 128); let max_value = !0u128 >> (128 - bits); @@ -1658,17 +1617,17 @@ impl<'a, 'tcx> TyLayout<'tcx> { // Locals variables which live across yields are stored // in the generator type as fields. These may be uninitialized // 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); } - match self.abi { + match layout.abi { Abi::Scalar(ref scalar) => { return Ok(scalar_component(scalar, Size::from_bytes(0))); } Abi::ScalarPair(ref a, ref b) => { 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, .. } => { @@ -1678,22 +1637,22 @@ impl<'a, 'tcx> TyLayout<'tcx> { } // 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 // (a discriminant), other unions are unsafe. - if let Variants::Single { .. } = self.variants { + if let Variants::Single { .. } = layout.variants { return Ok(None); } } - if let FieldPlacement::Array { .. } = self.fields { - if self.fields.count() > 0 { - return self.field(cx, 0)?.find_niche(cx, count); + if let FieldPlacement::Array { .. } = layout.fields { + if layout.fields.count() > 0 { + return self.find_niche(layout.field(self, 0)?, count); } } - for i in 0..self.fields.count() { - let r = self.field(cx, i)?.find_niche(cx, count)?; + for i in 0..layout.fields.count() { + let r = self.find_niche(layout.field(self, i)?, count)?; 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))); } } diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index b0a53445659..cc3fd3e0cdd 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -14,7 +14,7 @@ pub use self::Primitive::*; use spec::Target; use std::cmp; -use std::ops::{Add, Sub, Mul, AddAssign, RangeInclusive}; +use std::ops::{Add, Deref, Sub, Mul, AddAssign, RangeInclusive}; 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 { type Ty; type 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(self, cx: C, variant_index: usize) -> Self + where Ty: TyLayoutMethods<'a, C>, C: LayoutOf { + Ty::for_variant(self, cx, variant_index) + } + pub fn field(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) + } +} \ No newline at end of file