diff options
Diffstat (limited to 'src/librustc/ty/layout.rs')
| -rw-r--r-- | src/librustc/ty/layout.rs | 359 |
1 files changed, 199 insertions, 160 deletions
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index bd99ae0204a..eb22b6f2ce9 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -25,7 +25,7 @@ use std::fmt; use std::i64; use std::iter; use std::mem; -use std::ops::{Deref, Add, Sub, Mul, AddAssign, RangeInclusive}; +use std::ops::{Add, Sub, Mul, AddAssign, RangeInclusive}; use ich::StableHashingContext; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, @@ -856,7 +856,7 @@ impl<'a, 'tcx> Struct { // Is this the NonZero lang item wrapping a pointer or integer type? (_, &ty::TyAdt(def, _)) if Some(def.did) == tcx.lang_items().non_zero() => { let field = layout.field(cx, 0)?; - match *field { + match *field.layout { Scalar(value) => { Ok(Some((layout.fields.offset(0), value))) } @@ -965,7 +965,7 @@ impl<'a, 'tcx> Union { fields: I, scapegoat: Ty<'tcx>) -> Result<(), LayoutError<'tcx>> - where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> { + where I: Iterator<Item=Result<FullLayout<'a>, LayoutError<'tcx>>> { for (index, field) in fields.enumerate() { let field = field?; if field.is_unsized() { @@ -1061,8 +1061,80 @@ impl<'a> FieldPlacement<'a> { #[derive(Copy, Clone, Debug)] pub enum Abi { Scalar(Primitive), - Vector, - Aggregate + Vector { + element: Primitive, + count: u64 + }, + Aggregate { + /// If true, the size is exact, otherwise it's only a lower bound. + sized: bool, + align: Align, + primitive_align: Align, + size: Size + } +} + +impl Abi { + /// Returns true if the layout corresponds to an unsized type. + pub fn is_unsized(&self) -> bool { + match *self { + Abi::Scalar(_) | Abi::Vector {..} => false, + Abi::Aggregate { sized, .. } => !sized + } + } + + pub fn size<C: HasDataLayout>(&self, cx: C) -> Size { + let dl = cx.data_layout(); + + match *self { + Abi::Scalar(value) => value.size(dl), + + Abi::Vector { element, count } => { + let element_size = element.size(dl); + let vec_size = match element_size.checked_mul(count, dl) { + Some(size) => size, + None => bug!("Layout::size({:?}): {} * {} overflowed", + self, element_size.bytes(), count) + }; + vec_size.abi_align(self.align(dl)) + } + + Abi::Aggregate { size, .. } => size + } + } + + pub fn align<C: HasDataLayout>(&self, cx: C) -> Align { + let dl = cx.data_layout(); + + match *self { + Abi::Scalar(value) => value.align(dl), + + Abi::Vector { element, count } => { + let elem_size = element.size(dl); + let vec_size = match elem_size.checked_mul(count, dl) { + Some(size) => size, + None => bug!("Layout::align({:?}): {} * {} overflowed", + self, elem_size.bytes(), count) + }; + dl.vector_align(vec_size) + } + + Abi::Aggregate { align, .. } => align + } + } + + pub fn size_and_align<C: HasDataLayout>(&self, cx: C) -> (Size, Align) { + (self.size(cx), self.align(cx)) + } + + /// Returns alignment before repr alignment is applied + pub fn primitive_align<C: HasDataLayout>(&self, cx: C) -> Align { + match *self { + Abi::Aggregate { primitive_align, .. } => primitive_align, + + _ => self.align(cx.data_layout()) + } + } } /// Type layout, from which size and alignment can be cheaply computed. @@ -1247,19 +1319,63 @@ impl<'a, 'tcx> Layout { }; let abi = match *layout { Scalar(value) => Abi::Scalar(value), - Vector { .. } => Abi::Vector, + Vector { element, count } => Abi::Vector { element, count }, + + Array { sized, align, primitive_align, element_size, count, .. } => { + let size = match element_size.checked_mul(count, dl) { + Some(size) => size, + None => return Err(LayoutError::SizeOverflow(ty)) + }; + Abi::Aggregate { + sized, + align, + primitive_align, + size + } + } - Array { .. } | - FatPointer { .. } | - Univariant(_) | - UntaggedUnion(_) => Abi::Aggregate, + FatPointer(metadata) => { + // Effectively a (ptr, meta) tuple. + let align = Pointer.align(dl).max(metadata.align(dl)); + Abi::Aggregate { + sized: true, + align, + primitive_align: align, + size: (Pointer.size(dl).abi_align(metadata.align(dl)) + + metadata.size(dl)) + .abi_align(align) + } + } - General { discr, .. } | - NullablePointer { discr, .. } => { - if fields.offset(0).bytes() == 0 && discr.size(cx) == layout.size(cx) { + Univariant(ref st) => { + Abi::Aggregate { + sized: st.sized, + align: st.align, + primitive_align: st.primitive_align, + size: st.stride() + } + } + + UntaggedUnion(ref un ) => { + Abi::Aggregate { + sized: true, + align: un.align, + primitive_align: un.primitive_align, + size: un.stride() + } + } + + General { discr, align, primitive_align, size, .. } | + NullablePointer { discr, align, primitive_align, size, .. } => { + if fields.offset(0).bytes() == 0 && discr.size(cx) == size { Abi::Scalar(discr) } else { - Abi::Aggregate + Abi::Aggregate { + sized: true, + align, + primitive_align, + size + } } } }; @@ -1330,9 +1446,6 @@ impl<'a, 'tcx> Layout { let element = cx.layout_of(element)?; let element_size = element.size(dl); let count = count.val.to_const_int().unwrap().to_u64().unwrap(); - if element_size.checked_mul(count, dl).is_none() { - return Err(LayoutError::SizeOverflow(ty)); - } Array { sized: true, align: element.align(dl), @@ -1408,8 +1521,8 @@ impl<'a, 'tcx> Layout { // SIMD vector types. ty::TyAdt(def, ..) if def.repr.simd() => { let element = ty.simd_type(tcx); - match *cx.layout_of(element)? { - Scalar(value) => { + match cx.layout_of(element)?.abi { + Abi::Scalar(value) => { return success(Vector { element: value, count: ty.simd_size(tcx) as u64 @@ -1459,7 +1572,7 @@ impl<'a, 'tcx> Layout { let layout = if def.is_union() { let mut un = Union::new(dl, &def.repr); - un.extend(dl, variants[0].iter().map(|&f| Ok(f.layout)), ty)?; + un.extend(dl, variants[0].iter().map(|&f| Ok(f)), ty)?; UntaggedUnion(un) } else { Univariant(Struct::new(dl, &variants[0], &def.repr, kind, ty)?) @@ -1648,112 +1761,13 @@ impl<'a, 'tcx> Layout { success(layout) } - /// Returns true if the layout corresponds to an unsized type. - pub fn is_unsized(&self) -> bool { - match *self { - Scalar(_) | Vector {..} | FatPointer {..} | - UntaggedUnion {..} | General {..} | - NullablePointer {..} => false, - - Array { sized, .. } | - Univariant(Struct { sized, .. }) => !sized - } - } - - pub fn size<C: HasDataLayout>(&self, cx: C) -> Size { - let dl = cx.data_layout(); - - match *self { - Scalar(value) => { - value.size(dl) - } - - Vector { element, count } => { - let element_size = element.size(dl); - let vec_size = match element_size.checked_mul(count, dl) { - Some(size) => size, - None => bug!("Layout::size({:?}): {} * {} overflowed", - self, element_size.bytes(), count) - }; - vec_size.abi_align(self.align(dl)) - } - - Array { element_size, count, .. } => { - match element_size.checked_mul(count, dl) { - Some(size) => size, - None => bug!("Layout::size({:?}): {} * {} overflowed", - self, element_size.bytes(), count) - } - } - - FatPointer(metadata) => { - // Effectively a (ptr, meta) tuple. - (Pointer.size(dl).abi_align(metadata.align(dl)) + - metadata.size(dl)).abi_align(self.align(dl)) - } - - NullablePointer { size, .. } | - General { size, .. } => size, - UntaggedUnion(ref un) => un.stride(), - Univariant(ref variant) => variant.stride() - } - } - - pub fn align<C: HasDataLayout>(&self, cx: C) -> Align { - let dl = cx.data_layout(); - - match *self { - Scalar(value) => { - value.align(dl) - } - - Vector { element, count } => { - let elem_size = element.size(dl); - let vec_size = match elem_size.checked_mul(count, dl) { - Some(size) => size, - None => bug!("Layout::align({:?}): {} * {} overflowed", - self, elem_size.bytes(), count) - }; - dl.vector_align(vec_size) - } - - FatPointer(metadata) => { - // Effectively a (ptr, meta) tuple. - Pointer.align(dl).max(metadata.align(dl)) - } - - Array { align, .. } | - NullablePointer { align, .. } | - General { align, .. } => align, - UntaggedUnion(ref un) => un.align, - Univariant(ref variant) => variant.align - } - } - - pub fn size_and_align<C: HasDataLayout>(&self, cx: C) -> (Size, Align) { - (self.size(cx), self.align(cx)) - } - - /// Returns alignment before repr alignment is applied - pub fn primitive_align<C: HasDataLayout>(&self, cx: C) -> Align { - match *self { - Array { primitive_align, .. } | - NullablePointer { primitive_align, .. } | - General { primitive_align, .. } => primitive_align, - - Univariant(ref variant) => variant.primitive_align, - - _ => self.align(cx.data_layout()) - } - } - /// This is invoked by the `layout_raw` query to record the final /// layout of each type. #[inline] fn record_layout_for_printing(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, param_env: ty::ParamEnv<'tcx>, - layout: &Layout) { + layout: FullLayout) { // If we are running with `-Zprint-type-sizes`, record layouts for // dumping later. Ignore layouts that are done with non-empty // environments or non-monomorphic layouts, as the user only wants @@ -1773,7 +1787,7 @@ impl<'a, 'tcx> Layout { fn record_layout_for_printing_outlined(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, param_env: ty::ParamEnv<'tcx>, - layout: &Layout) { + layout: FullLayout) { // (delay format until we actually need it) let record = |kind, opt_discr_size, variants| { let type_desc = format!("{:?}", ty); @@ -1843,7 +1857,7 @@ impl<'a, 'tcx> Layout { } }; - match *layout { + match *layout.layout { Layout::Univariant(ref variant_layout) => { let variant_names = || { adt_def.variants.iter().map(|v|format!("{}", v.name)).collect::<Vec<_>>() @@ -1888,7 +1902,7 @@ impl<'a, 'tcx> Layout { variant_layout) }) .collect(); - record(adt_kind.into(), match *layout { + record(adt_kind.into(), match *layout.layout { Layout::General { discr, .. } => Some(discr.size(tcx)), _ => None }, variant_infos); @@ -2075,13 +2089,6 @@ pub struct FullLayout<'tcx> { pub abi: Abi, } -impl<'tcx> Deref for FullLayout<'tcx> { - type Target = Layout; - fn deref(&self) -> &Layout { - self.layout - } -} - pub trait HasTyCtxt<'tcx>: HasDataLayout { fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>; } @@ -2127,6 +2134,13 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (TyCtxt<'a, 'tcx, 'tcx>, ty::ParamEnv<'tcx let ty = tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all()); let cached = tcx.layout_raw(param_env.reveal_all().and(ty))?; + let layout = FullLayout { + ty, + variant_index: None, + layout: cached.layout, + fields: cached.fields, + abi: cached.abi + }; // NB: This recording is normally disabled; when enabled, it // can however trigger recursive invocations of `layout_of`. @@ -2134,15 +2148,9 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (TyCtxt<'a, 'tcx, 'tcx>, ty::ParamEnv<'tcx // completed, to avoid problems around recursive structures // and the like. (Admitedly, I wasn't able to reproduce a problem // here, but it seems like the right thing to do. -nmatsakis) - Layout::record_layout_for_printing(tcx, ty, param_env, cached.layout); + Layout::record_layout_for_printing(tcx, ty, param_env, layout); - Ok(FullLayout { - ty, - variant_index: None, - layout: cached.layout, - fields: cached.fields, - abi: cached.abi - }) + Ok(layout) } } @@ -2158,6 +2166,13 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>, let ty = tcx_at.tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all()); let cached = tcx_at.layout_raw(param_env.reveal_all().and(ty))?; + let layout = FullLayout { + ty, + variant_index: None, + layout: cached.layout, + fields: cached.fields, + abi: cached.abi + }; // NB: This recording is normally disabled; when enabled, it // can however trigger recursive invocations of `layout_of`. @@ -2165,15 +2180,9 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>, // completed, to avoid problems around recursive structures // and the like. (Admitedly, I wasn't able to reproduce a problem // here, but it seems like the right thing to do. -nmatsakis) - Layout::record_layout_for_printing(tcx_at.tcx, ty, param_env, cached.layout); + Layout::record_layout_for_printing(tcx_at.tcx, ty, param_env, layout); - Ok(FullLayout { - ty, - variant_index: None, - layout: cached.layout, - fields: cached.fields, - abi: cached.abi - }) + Ok(layout) } } @@ -2189,27 +2198,29 @@ impl<'a, 'tcx> FullLayout<'tcx> { variants[variant_index].fields.len() }; - let fields = match *self.layout { - Univariant(ref variant) => { - FieldPlacement::Arbitrary { - offsets: &variant.offsets - } - } + let (fields, abi) = match *self.layout { + Univariant(_) => (self.fields, self.abi), NullablePointer { ref variants, .. } | General { ref variants, .. } => { - FieldPlacement::Arbitrary { - offsets: &variants[variant_index].offsets - } + let variant = &variants[variant_index]; + (FieldPlacement::Arbitrary { + offsets: &variant.offsets + }, Abi::Aggregate { + sized: true, + align: variant.align, + primitive_align: variant.primitive_align, + size: variant.stride(), + }) } - _ => FieldPlacement::union(count) + _ => (FieldPlacement::union(count), self.abi) }; FullLayout { variant_index: Some(variant_index), fields, - abi: Abi::Aggregate, + abi, ..*self } } @@ -2313,6 +2324,28 @@ impl<'a, 'tcx> FullLayout<'tcx> { -> C::FullLayout { cx.layout_of(self.field_type_unnormalized(cx.tcx(), i)) } + + /// Returns true if the layout corresponds to an unsized type. + pub fn is_unsized(&self) -> bool { + self.abi.is_unsized() + } + + pub fn size<C: HasDataLayout>(&self, cx: C) -> Size { + self.abi.size(cx) + } + + pub fn align<C: HasDataLayout>(&self, cx: C) -> Align { + self.abi.align(cx) + } + + pub fn size_and_align<C: HasDataLayout>(&self, cx: C) -> (Size, Align) { + self.abi.size_and_align(cx) + } + + /// Returns alignment before repr alignment is applied + pub fn primitive_align<C: HasDataLayout>(&self, cx: C) -> Align { + self.abi.primitive_align(cx) + } } impl<'gcx> HashStable<StableHashingContext<'gcx>> for Layout @@ -2411,12 +2444,18 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Abi { mem::discriminant(self).hash_stable(hcx, hasher); match *self { - Scalar(value) => { + Scalar(ref value) => { value.hash_stable(hcx, hasher); } - Vector => { + Vector { ref element, count } => { + element.hash_stable(hcx, hasher); + count.hash_stable(hcx, hasher); } - Aggregate => { + Aggregate { sized, size, align, primitive_align } => { + sized.hash_stable(hcx, hasher); + size.hash_stable(hcx, hasher); + align.hash_stable(hcx, hasher); + primitive_align.hash_stable(hcx, hasher); } } } |
