Auto merge of #47915 - eddyb:layout-of, r=nikomatsakis

rustc: prefer ParamEnvAnd and LayoutCx over tuples for LayoutOf.

This PR provides `tcx.layout_of(param_env.and(ty))` as the idiomatic replacement for the existing `(tcx, param_env).layout_of(ty)` and removes fragile (coherence-wise) layout-related tuple impls.

r? @nikomatsakis
This commit is contained in:
bors 2018-02-04 03:33:44 +00:00
commit 9af374abf9
8 changed files with 107 additions and 84 deletions

View File

@ -631,7 +631,7 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for &'a LateContext<'a, 'tcx> {
type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
(self.tcx, self.param_env.reveal_all()).layout_of(ty)
self.tcx.layout_of(self.param_env.and(ty))
}
}

View File

@ -895,7 +895,8 @@ fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
tcx.layout_depth.set(depth+1);
let layout = LayoutDetails::compute_uncached(tcx, param_env, ty);
let cx = LayoutCx { tcx, param_env };
let layout = cx.layout_raw_uncached(ty);
tcx.layout_depth.set(depth);
layout
@ -908,13 +909,18 @@ pub fn provide(providers: &mut ty::maps::Providers) {
};
}
impl<'a, 'tcx> LayoutDetails {
fn compute_uncached(tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>)
-> Result<&'tcx Self, LayoutError<'tcx>> {
let cx = (tcx, param_env);
let dl = cx.data_layout();
#[derive(Copy, Clone)]
pub struct LayoutCx<'tcx, C> {
pub tcx: C,
pub param_env: ty::ParamEnv<'tcx>
}
impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
fn layout_raw_uncached(self, ty: Ty<'tcx>)
-> Result<&'tcx LayoutDetails, LayoutError<'tcx>> {
let tcx = self.tcx;
let param_env = self.param_env;
let dl = self.data_layout();
let scalar_unit = |value: Primitive| {
let bits = value.size(dl).bits();
assert!(bits <= 128);
@ -924,7 +930,7 @@ impl<'a, 'tcx> LayoutDetails {
}
};
let scalar = |value: Primitive| {
tcx.intern_layout(LayoutDetails::scalar(cx, scalar_unit(value)))
tcx.intern_layout(LayoutDetails::scalar(self, scalar_unit(value)))
};
let scalar_pair = |a: Scalar, b: Scalar| {
let align = a.value.align(dl).max(b.value.align(dl)).max(dl.aggregate_align);
@ -1158,13 +1164,13 @@ impl<'a, 'tcx> LayoutDetails {
Ok(match ty.sty {
// Basic scalars.
ty::TyBool => {
tcx.intern_layout(LayoutDetails::scalar(cx, Scalar {
tcx.intern_layout(LayoutDetails::scalar(self, Scalar {
value: Int(I8, false),
valid_range: 0..=1
}))
}
ty::TyChar => {
tcx.intern_layout(LayoutDetails::scalar(cx, Scalar {
tcx.intern_layout(LayoutDetails::scalar(self, Scalar {
value: Int(I32, false),
valid_range: 0..=0x10FFFF
}))
@ -1180,7 +1186,7 @@ impl<'a, 'tcx> LayoutDetails {
ty::TyFnPtr(_) => {
let mut ptr = scalar_unit(Pointer);
ptr.valid_range.start = 1;
tcx.intern_layout(LayoutDetails::scalar(cx, ptr))
tcx.intern_layout(LayoutDetails::scalar(self, ptr))
}
// The never type.
@ -1198,13 +1204,13 @@ impl<'a, 'tcx> LayoutDetails {
let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env);
if pointee.is_sized(tcx, param_env, DUMMY_SP) {
return Ok(tcx.intern_layout(LayoutDetails::scalar(cx, data_ptr)));
return Ok(tcx.intern_layout(LayoutDetails::scalar(self, data_ptr)));
}
let unsized_part = tcx.struct_tail(pointee);
let metadata = match unsized_part.sty {
ty::TyForeign(..) => {
return Ok(tcx.intern_layout(LayoutDetails::scalar(cx, data_ptr)));
return Ok(tcx.intern_layout(LayoutDetails::scalar(self, data_ptr)));
}
ty::TySlice(_) | ty::TyStr => {
scalar_unit(Int(dl.ptr_sized_integer(), false))
@ -1230,7 +1236,7 @@ impl<'a, 'tcx> LayoutDetails {
}
}
let element = cx.layout_of(element)?;
let element = self.layout_of(element)?;
let count = count.val.to_const_int().unwrap().to_u64().unwrap();
let size = element.size.checked_mul(count, dl)
.ok_or(LayoutError::SizeOverflow(ty))?;
@ -1247,7 +1253,7 @@ impl<'a, 'tcx> LayoutDetails {
})
}
ty::TySlice(element) => {
let element = cx.layout_of(element)?;
let element = self.layout_of(element)?;
tcx.intern_layout(LayoutDetails {
variants: Variants::Single { index: 0 },
fields: FieldPlacement::Array {
@ -1289,14 +1295,14 @@ impl<'a, 'tcx> LayoutDetails {
// Tuples, generators and closures.
ty::TyGenerator(def_id, ref substs, _) => {
let tys = substs.field_tys(def_id, tcx);
univariant(&tys.map(|ty| cx.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
univariant(&tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
&ReprOptions::default(),
StructKind::AlwaysSized)?
}
ty::TyClosure(def_id, ref substs) => {
let tys = substs.upvar_tys(def_id, tcx);
univariant(&tys.map(|ty| cx.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
univariant(&tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
&ReprOptions::default(),
StructKind::AlwaysSized)?
}
@ -1308,13 +1314,13 @@ impl<'a, 'tcx> LayoutDetails {
StructKind::MaybeUnsized
};
univariant(&tys.iter().map(|ty| cx.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
univariant(&tys.iter().map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
&ReprOptions::default(), kind)?
}
// SIMD vector types.
ty::TyAdt(def, ..) if def.repr.simd() => {
let element = cx.layout_of(ty.simd_type(tcx))?;
let element = self.layout_of(ty.simd_type(tcx))?;
let count = ty.simd_size(tcx) as u64;
assert!(count > 0);
let scalar = match element.abi {
@ -1350,7 +1356,7 @@ impl<'a, 'tcx> LayoutDetails {
// Cache the field layouts.
let variants = def.variants.iter().map(|v| {
v.fields.iter().map(|field| {
cx.layout_of(field.ty(tcx, substs))
self.layout_of(field.ty(tcx, substs))
}).collect::<Result<Vec<_>, _>>()
}).collect::<Result<Vec<_>, _>>()?;
@ -1430,7 +1436,7 @@ impl<'a, 'tcx> LayoutDetails {
let mut st = univariant_uninterned(&variants[v], &def.repr, kind)?;
st.variants = Variants::Single { index: v };
// Exclude 0 from the range of a newtype ABI NonZero<T>.
if Some(def.did) == cx.tcx().lang_items().non_zero() {
if Some(def.did) == self.tcx.lang_items().non_zero() {
match st.abi {
Abi::Scalar(ref mut scalar) |
Abi::ScalarPair(ref mut scalar, _) => {
@ -1482,7 +1488,7 @@ impl<'a, 'tcx> LayoutDetails {
let count = (niche_variants.end - niche_variants.start + 1) as u128;
for (field_index, field) in variants[i].iter().enumerate() {
let (offset, niche, niche_start) =
match field.find_niche(cx, count)? {
match field.find_niche(self, count)? {
Some(niche) => niche,
None => continue
};
@ -1687,56 +1693,49 @@ impl<'a, 'tcx> LayoutDetails {
/// 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: TyLayout<'tcx>) {
fn record_layout_for_printing(self, layout: TyLayout<'tcx>) {
// 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
// to see the stuff resulting from the final trans session.
if
!tcx.sess.opts.debugging_opts.print_type_sizes ||
ty.has_param_types() ||
ty.has_self_ty() ||
!param_env.caller_bounds.is_empty()
!self.tcx.sess.opts.debugging_opts.print_type_sizes ||
layout.ty.has_param_types() ||
layout.ty.has_self_ty() ||
!self.param_env.caller_bounds.is_empty()
{
return;
}
Self::record_layout_for_printing_outlined(tcx, ty, param_env, layout)
self.record_layout_for_printing_outlined(layout)
}
fn record_layout_for_printing_outlined(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
layout: TyLayout<'tcx>) {
let cx = (tcx, param_env);
fn record_layout_for_printing_outlined(self, layout: TyLayout<'tcx>) {
// (delay format until we actually need it)
let record = |kind, opt_discr_size, variants| {
let type_desc = format!("{:?}", ty);
tcx.sess.code_stats.borrow_mut().record_type_size(kind,
type_desc,
layout.align,
layout.size,
opt_discr_size,
variants);
let type_desc = format!("{:?}", layout.ty);
self.tcx.sess.code_stats.borrow_mut().record_type_size(kind,
type_desc,
layout.align,
layout.size,
opt_discr_size,
variants);
};
let adt_def = match ty.sty {
let adt_def = match layout.ty.sty {
ty::TyAdt(ref adt_def, _) => {
debug!("print-type-size t: `{:?}` process adt", ty);
debug!("print-type-size t: `{:?}` process adt", layout.ty);
adt_def
}
ty::TyClosure(..) => {
debug!("print-type-size t: `{:?}` record closure", ty);
debug!("print-type-size t: `{:?}` record closure", layout.ty);
record(DataTypeKind::Closure, None, vec![]);
return;
}
_ => {
debug!("print-type-size t: `{:?}` skip non-nominal", ty);
debug!("print-type-size t: `{:?}` skip non-nominal", layout.ty);
return;
}
};
@ -1748,7 +1747,7 @@ impl<'a, 'tcx> LayoutDetails {
layout: TyLayout<'tcx>| {
let mut min_size = Size::from_bytes(0);
let field_info: Vec<_> = flds.iter().enumerate().map(|(i, &name)| {
match layout.field(cx, i) {
match layout.field(self, i) {
Err(err) => {
bug!("no layout found for field {}: `{:?}`", name, err);
}
@ -1808,18 +1807,18 @@ impl<'a, 'tcx> LayoutDetails {
Variants::NicheFilling { .. } |
Variants::Tagged { .. } => {
debug!("print-type-size `{:#?}` adt general variants def {}",
ty, adt_def.variants.len());
layout.ty, adt_def.variants.len());
let variant_infos: Vec<_> =
adt_def.variants.iter().enumerate().map(|(i, variant_def)| {
let fields: Vec<_> =
variant_def.fields.iter().map(|f| f.name).collect();
build_variant_info(Some(variant_def.name),
&fields,
layout.for_variant(cx, i))
layout.for_variant(self, i))
})
.collect();
record(adt_kind.into(), match layout.variants {
Variants::Tagged { ref discr, .. } => Some(discr.value.size(tcx)),
Variants::Tagged { ref discr, .. } => Some(discr.value.size(self)),
_ => None
}, variant_infos);
}
@ -1855,7 +1854,7 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> {
assert!(!ty.has_infer_types());
// First try computing a static layout.
let err = match (tcx, param_env).layout_of(ty) {
let err = match tcx.layout_of(param_env.and(ty)) {
Ok(layout) => {
return Ok(SizeSkeleton::Known(layout.size));
}
@ -2001,15 +2000,15 @@ impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> {
}
}
impl<'a, 'gcx, 'tcx, T: Copy> HasDataLayout for (TyCtxt<'a, 'gcx, 'tcx>, T) {
impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> {
fn data_layout(&self) -> &TargetDataLayout {
self.0.data_layout()
self.tcx.data_layout()
}
}
impl<'a, 'gcx, 'tcx, T: Copy> HasTyCtxt<'gcx> for (TyCtxt<'a, 'gcx, 'tcx>, T) {
impl<'gcx, 'tcx, T: HasTyCtxt<'gcx>> HasTyCtxt<'gcx> for LayoutCx<'tcx, T> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
self.0.tcx()
self.tcx.tcx()
}
}
@ -2042,17 +2041,15 @@ pub trait LayoutOf<T> {
fn layout_of(self, ty: T) -> Self::TyLayout;
}
impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (TyCtxt<'a, 'tcx, 'tcx>, ty::ParamEnv<'tcx>) {
impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
/// Computes the layout of a type. Note that this implicitly
/// executes in "reveal all" mode.
#[inline]
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
let (tcx, param_env) = self;
let ty = tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all());
let details = tcx.layout_raw(param_env.reveal_all().and(ty))?;
let param_env = self.param_env.reveal_all();
let ty = self.tcx.normalize_associated_type_in_env(&ty, param_env);
let details = self.tcx.layout_raw(param_env.and(ty))?;
let layout = TyLayout {
ty,
details
@ -2064,24 +2061,21 @@ 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)
LayoutDetails::record_layout_for_printing(tcx, ty, param_env, layout);
self.record_layout_for_printing(layout);
Ok(layout)
}
}
impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>,
ty::ParamEnv<'tcx>) {
impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for LayoutCx<'tcx, ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>> {
type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
/// Computes the layout of a type. Note that this implicitly
/// executes in "reveal all" mode.
#[inline]
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
let (tcx_at, param_env) = self;
let ty = tcx_at.tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all());
let details = tcx_at.layout_raw(param_env.reveal_all().and(ty))?;
let param_env = self.param_env.reveal_all();
let ty = self.tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all());
let details = self.tcx.layout_raw(param_env.reveal_all().and(ty))?;
let layout = TyLayout {
ty,
details
@ -2093,12 +2087,45 @@ 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)
LayoutDetails::record_layout_for_printing(tcx_at.tcx, ty, param_env, layout);
let cx = LayoutCx {
tcx: *self.tcx,
param_env: self.param_env
};
cx.record_layout_for_printing(layout);
Ok(layout)
}
}
// Helper (inherent) `layout_of` methods to avoid pushing `LayoutCx` to users.
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
/// Computes the layout of a type. Note that this implicitly
/// executes in "reveal all" mode.
#[inline]
pub fn layout_of(self, param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
-> Result<TyLayout<'tcx>, LayoutError<'tcx>> {
let cx = LayoutCx {
tcx: self,
param_env: param_env_and_ty.param_env
};
cx.layout_of(param_env_and_ty.value)
}
}
impl<'a, 'tcx> ty::maps::TyCtxtAt<'a, 'tcx, 'tcx> {
/// Computes the layout of a type. Note that this implicitly
/// executes in "reveal all" mode.
#[inline]
pub fn layout_of(self, param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
-> Result<TyLayout<'tcx>, LayoutError<'tcx>> {
let cx = LayoutCx {
tcx: self,
param_env: param_env_and_ty.param_env
};
cx.layout_of(param_env_and_ty.value)
}
}
impl<'a, 'tcx> TyLayout<'tcx> {
pub fn for_variant<C>(&self, cx: C, variant_index: usize) -> Self
where C: LayoutOf<Ty<'tcx>> + HasTyCtxt<'tcx>,

View File

@ -17,7 +17,6 @@ use rustc::hir::map::blocks::FnLikeNode;
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::LayoutOf;
use rustc::ty::util::IntTypeExt;
use rustc::ty::subst::{Substs, Subst};
use rustc::util::common::ErrorReported;
@ -313,7 +312,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic {
let layout_of = |ty: Ty<'tcx>| {
let ty = tcx.erase_regions(&ty);
(tcx.at(e.span), cx.param_env).layout_of(ty).map_err(|err| {
tcx.at(e.span).layout_of(cx.param_env.and(ty)).map_err(|err| {
ConstEvalErr { span: e.span, kind: LayoutError(err) }
})
};

View File

@ -437,8 +437,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
// repr(transparent) types are allowed to have arbitrary ZSTs, not just
// PhantomData -- skip checking all ZST fields
if def.repr.transparent() {
let is_zst = (cx, cx.param_env(field.did))
.layout_of(field_ty)
let is_zst = cx
.layout_of(cx.param_env(field.did).and(field_ty))
.map(|layout| layout.is_zst())
.unwrap_or(false);
if is_zst {

View File

@ -172,7 +172,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> LayoutOf<Ty<'tcx>> for &'a EvalContext<'a, 'tcx
type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
(self.tcx, self.param_env).layout_of(ty)
self.tcx.layout_of(self.param_env.and(ty))
.map_err(|layout| EvalErrorKind::Layout(layout).into())
}
}

View File

@ -19,7 +19,6 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc::mir::*;
use rustc::mir::visit::*;
use rustc::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
use rustc::ty::layout::LayoutOf;
use rustc::ty::subst::{Subst,Substs};
use std::collections::VecDeque;
@ -655,7 +654,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>) -> Option<u64> {
(tcx, param_env).layout_of(ty).ok().map(|layout| layout.size.bytes())
tcx.layout_of(param_env.and(ty)).ok().map(|layout| layout.size.bytes())
}
fn subst_and_normalize<'a, 'tcx: 'a>(

View File

@ -464,8 +464,7 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for &'a CodegenCx<'a, 'tcx> {
type TyLayout = TyLayout<'tcx>;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
(self.tcx, ty::ParamEnv::empty(traits::Reveal::All))
.layout_of(ty)
self.tcx.layout_of(ty::ParamEnv::empty(traits::Reveal::All).and(ty))
.unwrap_or_else(|e| match e {
LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()),
_ => bug!("failed to get layout for `{}`: {}", ty, e)

View File

@ -100,7 +100,6 @@ use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::maps::Providers;
use rustc::ty::util::{Representability, IntTypeExt};
use rustc::ty::layout::LayoutOf;
use errors::{DiagnosticBuilder, DiagnosticId};
use require_c_abi_if_variadic;
@ -1553,7 +1552,7 @@ fn check_transparent<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: De
let field_infos: Vec<_> = adt.non_enum_variant().fields.iter().map(|field| {
let ty = field.ty(tcx, Substs::identity_for_item(tcx, field.did));
let param_env = tcx.param_env(field.did);
let layout = (tcx, param_env).layout_of(ty);
let layout = tcx.layout_of(param_env.and(ty));
// We are currently checking the type this field came from, so it must be local
let span = tcx.hir.span_if_local(field.did).unwrap();
let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false);