rewrite layout to take a (param-env, ty) pair instead of infcx

This commit is contained in:
Niko Matsakis 2017-05-19 17:27:25 -04:00
parent 6c4b961eff
commit 541523d10d
9 changed files with 227 additions and 214 deletions

View File

@ -112,6 +112,7 @@ pub enum DepNode<D: Clone + Debug> {
IsSized(D), IsSized(D),
IsFreeze(D), IsFreeze(D),
NeedsDrop(D), NeedsDrop(D),
Layout(D),
// The set of impls for a given trait. Ultimately, it would be // The set of impls for a given trait. Ultimately, it would be
// nice to get more fine-grained here (e.g., to include a // nice to get more fine-grained here (e.g., to include a
@ -241,6 +242,7 @@ impl<D: Clone + Debug> DepNode<D> {
IsSized(ref d) => op(d).map(IsSized), IsSized(ref d) => op(d).map(IsSized),
IsFreeze(ref d) => op(d).map(IsFreeze), IsFreeze(ref d) => op(d).map(IsFreeze),
NeedsDrop(ref d) => op(d).map(NeedsDrop), NeedsDrop(ref d) => op(d).map(NeedsDrop),
Layout(ref d) => op(d).map(Layout),
Hir(ref d) => op(d).map(Hir), Hir(ref d) => op(d).map(Hir),
HirBody(ref d) => op(d).map(HirBody), HirBody(ref d) => op(d).map(HirBody),
MetaData(ref d) => op(d).map(MetaData), MetaData(ref d) => op(d).map(MetaData),

View File

@ -10,7 +10,6 @@
use hir::def::Def; use hir::def::Def;
use hir::def_id::DefId; use hir::def_id::DefId;
use infer::InferCtxt;
use ty::{self, Ty, TyCtxt}; use ty::{self, Ty, TyCtxt};
use ty::layout::{LayoutError, Pointer, SizeSkeleton}; use ty::layout::{LayoutError, Pointer, SizeSkeleton};
@ -30,8 +29,10 @@ struct ItemVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx> tcx: TyCtxt<'a, 'tcx, 'tcx>
} }
struct ExprVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { struct ExprVisitor<'a, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx> tcx: TyCtxt<'a, 'tcx, 'tcx>,
tables: &'tcx ty::TypeckTables<'tcx>,
param_env: ty::ParamEnv<'tcx>,
} }
/// If the type is `Option<T>`, it will return `T`, otherwise /// If the type is `Option<T>`, it will return `T`, otherwise
@ -63,18 +64,18 @@ fn unpack_option_like<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty ty
} }
impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { impl<'a, 'tcx> ExprVisitor<'a, 'tcx> {
fn def_id_is_transmute(&self, def_id: DefId) -> bool { fn def_id_is_transmute(&self, def_id: DefId) -> bool {
let intrinsic = match self.infcx.tcx.type_of(def_id).sty { let intrinsic = match self.tcx.type_of(def_id).sty {
ty::TyFnDef(.., bfty) => bfty.abi() == RustIntrinsic, ty::TyFnDef(.., bfty) => bfty.abi() == RustIntrinsic,
_ => return false _ => return false
}; };
intrinsic && self.infcx.tcx.item_name(def_id) == "transmute" intrinsic && self.tcx.item_name(def_id) == "transmute"
} }
fn check_transmute(&self, span: Span, from: Ty<'gcx>, to: Ty<'gcx>) { fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) {
let sk_from = SizeSkeleton::compute(from, self.infcx); let sk_from = SizeSkeleton::compute(from, self.tcx, self.param_env);
let sk_to = SizeSkeleton::compute(to, self.infcx); let sk_to = SizeSkeleton::compute(to, self.tcx, self.param_env);
// Check for same size using the skeletons. // Check for same size using the skeletons.
if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) { if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
@ -84,11 +85,11 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
// Special-case transmutting from `typeof(function)` and // Special-case transmutting from `typeof(function)` and
// `Option<typeof(function)>` to present a clearer error. // `Option<typeof(function)>` to present a clearer error.
let from = unpack_option_like(self.infcx.tcx.global_tcx(), from); let from = unpack_option_like(self.tcx.global_tcx(), from);
match (&from.sty, sk_to) { match (&from.sty, sk_to) {
(&ty::TyFnDef(..), SizeSkeleton::Known(size_to)) (&ty::TyFnDef(..), SizeSkeleton::Known(size_to))
if size_to == Pointer.size(self.infcx) => { if size_to == Pointer.size(self.tcx) => {
struct_span_err!(self.infcx.tcx.sess, span, E0591, struct_span_err!(self.tcx.sess, span, E0591,
"`{}` is zero-sized and can't be transmuted to `{}`", "`{}` is zero-sized and can't be transmuted to `{}`",
from, to) from, to)
.span_note(span, "cast with `as` to a pointer instead") .span_note(span, "cast with `as` to a pointer instead")
@ -100,7 +101,7 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
} }
// Try to display a sensible error with as much information as possible. // Try to display a sensible error with as much information as possible.
let skeleton_string = |ty: Ty<'gcx>, sk| { let skeleton_string = |ty: Ty<'tcx>, sk| {
match sk { match sk {
Ok(SizeSkeleton::Known(size)) => { Ok(SizeSkeleton::Known(size)) => {
format!("{} bits", size.bits()) format!("{} bits", size.bits())
@ -119,7 +120,7 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
} }
}; };
struct_span_err!(self.infcx.tcx.sess, span, E0512, struct_span_err!(self.tcx.sess, span, E0512,
"transmute called with differently sized types: \ "transmute called with differently sized types: \
{} ({}) to {} ({})", {} ({}) to {} ({})",
from, skeleton_string(from, sk_from), from, skeleton_string(from, sk_from),
@ -138,32 +139,30 @@ impl<'a, 'tcx> Visitor<'tcx> for ItemVisitor<'a, 'tcx> {
} }
fn visit_nested_body(&mut self, body_id: hir::BodyId) { fn visit_nested_body(&mut self, body_id: hir::BodyId) {
let owner_def_id = self.tcx.hir.body_owner_def_id(body_id);
let body = self.tcx.hir.body(body_id); let body = self.tcx.hir.body(body_id);
self.tcx.infer_ctxt(body_id).enter(|infcx| { let param_env = self.tcx.param_env(owner_def_id);
let mut visitor = ExprVisitor { let tables = self.tcx.typeck_tables_of(owner_def_id);
infcx: &infcx ExprVisitor { tcx: self.tcx, param_env, tables }.visit_body(body);
};
visitor.visit_body(body);
});
self.visit_body(body); self.visit_body(body);
} }
} }
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for ExprVisitor<'a, 'gcx, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::None NestedVisitorMap::None
} }
fn visit_expr(&mut self, expr: &'gcx hir::Expr) { fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
let def = if let hir::ExprPath(ref qpath) = expr.node { let def = if let hir::ExprPath(ref qpath) = expr.node {
self.infcx.tables.borrow().qpath_def(qpath, expr.id) self.tables.qpath_def(qpath, expr.id)
} else { } else {
Def::Err Def::Err
}; };
match def { match def {
Def::Fn(did) if self.def_id_is_transmute(did) => { Def::Fn(did) if self.def_id_is_transmute(did) => {
let typ = self.infcx.tables.borrow().node_id_to_type(expr.id); let typ = self.tables.node_id_to_type(expr.id);
let typ = self.infcx.tcx.lift_to_global(&typ).unwrap(); let typ = self.tcx.lift_to_global(&typ).unwrap();
match typ.sty { match typ.sty {
ty::TyFnDef(.., sig) if sig.abi() == RustIntrinsic => { ty::TyFnDef(.., sig) if sig.abi() == RustIntrinsic => {
let from = sig.inputs().skip_binder()[0]; let from = sig.inputs().skip_binder()[0];

View File

@ -12,9 +12,7 @@ pub use self::Integer::*;
pub use self::Layout::*; pub use self::Layout::*;
pub use self::Primitive::*; pub use self::Primitive::*;
use infer::InferCtxt;
use session::Session; use session::Session;
use traits;
use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, ReprFlags}; use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, ReprFlags};
use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::ast::{FloatTy, IntTy, UintTy};
@ -212,6 +210,12 @@ impl<'a> HasDataLayout for &'a TargetDataLayout {
} }
} }
impl<'a, 'tcx> HasDataLayout for TyCtxt<'a, 'tcx, 'tcx> {
fn data_layout(&self) -> &TargetDataLayout {
&self.data_layout
}
}
/// Endianness of the target, which must match cfg(target-endian). /// Endianness of the target, which must match cfg(target-endian).
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum Endian { pub enum Endian {
@ -457,8 +461,12 @@ impl Integer {
/// signed discriminant range and #[repr] attribute. /// signed discriminant range and #[repr] attribute.
/// N.B.: u64 values above i64::MAX will be treated as signed, but /// N.B.: u64 values above i64::MAX will be treated as signed, but
/// that shouldn't affect anything, other than maybe debuginfo. /// that shouldn't affect anything, other than maybe debuginfo.
fn repr_discr(tcx: TyCtxt, ty: Ty, repr: &ReprOptions, min: i64, max: i64) fn repr_discr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-> (Integer, bool) { ty: Ty<'tcx>,
repr: &ReprOptions,
min: i64,
max: i64)
-> (Integer, bool) {
// Theoretically, negative values could be larger in unsigned representation // Theoretically, negative values could be larger in unsigned representation
// than the unsigned representation of the signed minimum. However, if there // than the unsigned representation of the signed minimum. However, if there
// are any negative values, the only valid unsigned representation is u64 // are any negative values, the only valid unsigned representation is u64
@ -583,10 +591,13 @@ enum StructKind {
EnumVariant, EnumVariant,
} }
impl<'a, 'gcx, 'tcx> Struct { impl<'a, 'tcx> Struct {
fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>, fn new(dl: &TargetDataLayout,
repr: &ReprOptions, kind: StructKind, fields: &Vec<&'a Layout>,
scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> { repr: &ReprOptions,
kind: StructKind,
scapegoat: Ty<'tcx>)
-> Result<Struct, LayoutError<'tcx>> {
if repr.packed() && repr.align > 0 { if repr.packed() && repr.align > 0 {
bug!("Struct cannot be packed and aligned"); bug!("Struct cannot be packed and aligned");
} }
@ -723,8 +734,8 @@ impl<'a, 'gcx, 'tcx> Struct {
/// Determine whether a structure would be zero-sized, given its fields. /// Determine whether a structure would be zero-sized, given its fields.
fn would_be_zero_sized<I>(dl: &TargetDataLayout, fields: I) fn would_be_zero_sized<I>(dl: &TargetDataLayout, fields: I)
-> Result<bool, LayoutError<'gcx>> -> Result<bool, LayoutError<'tcx>>
where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> { where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {
for field in fields { for field in fields {
let field = field?; let field = field?;
if field.is_unsized() || field.size(dl).bytes() > 0 { if field.is_unsized() || field.size(dl).bytes() > 0 {
@ -764,11 +775,11 @@ impl<'a, 'gcx, 'tcx> Struct {
/// The tuple is `(path, source_path)`, /// The tuple is `(path, source_path)`,
/// where `path` is in memory order and `source_path` in source order. /// where `path` is in memory order and `source_path` in source order.
// FIXME(eddyb) track value ranges and traverse already optimized enums. // FIXME(eddyb) track value ranges and traverse already optimized enums.
fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>, fn non_zero_field_in_type(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty: Ty<'gcx>) param_env: ty::ParamEnv<'tcx>,
-> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>> { ty: Ty<'tcx>)
let tcx = infcx.tcx.global_tcx(); -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'tcx>> {
match (ty.layout(infcx)?, &ty.sty) { match (ty.layout(tcx, param_env)?, &ty.sty) {
(&Scalar { non_zero: true, .. }, _) | (&Scalar { non_zero: true, .. }, _) |
(&CEnum { non_zero: true, .. }, _) => Ok(Some((vec![], vec![]))), (&CEnum { non_zero: true, .. }, _) => Ok(Some((vec![], vec![]))),
(&FatPointer { non_zero: true, .. }, _) => { (&FatPointer { non_zero: true, .. }, _) => {
@ -779,7 +790,7 @@ impl<'a, 'gcx, 'tcx> Struct {
(&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) => { (&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) => {
let fields = &def.struct_variant().fields; let fields = &def.struct_variant().fields;
assert_eq!(fields.len(), 1); assert_eq!(fields.len(), 1);
match *fields[0].ty(tcx, substs).layout(infcx)? { match *fields[0].ty(tcx, substs).layout(tcx, param_env)? {
// FIXME(eddyb) also allow floating-point types here. // FIXME(eddyb) also allow floating-point types here.
Scalar { value: Int(_), non_zero: false } | Scalar { value: Int(_), non_zero: false } |
Scalar { value: Pointer, non_zero: false } => { Scalar { value: Pointer, non_zero: false } => {
@ -796,37 +807,49 @@ impl<'a, 'gcx, 'tcx> Struct {
// Perhaps one of the fields of this struct is non-zero // Perhaps one of the fields of this struct is non-zero
// let's recurse and find out // let's recurse and find out
(&Univariant { ref variant, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => { (&Univariant { ref variant, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => {
Struct::non_zero_field_paths(infcx, def.struct_variant().fields Struct::non_zero_field_paths(
.iter().map(|field| { tcx,
field.ty(tcx, substs) param_env,
}), def.struct_variant().fields.iter().map(|field| {
Some(&variant.memory_index[..])) field.ty(tcx, substs)
}),
Some(&variant.memory_index[..]))
} }
// Perhaps one of the upvars of this closure is non-zero // Perhaps one of the upvars of this closure is non-zero
(&Univariant { ref variant, .. }, &ty::TyClosure(def, substs)) => { (&Univariant { ref variant, .. }, &ty::TyClosure(def, substs)) => {
let upvar_tys = substs.upvar_tys(def, tcx); let upvar_tys = substs.upvar_tys(def, tcx);
Struct::non_zero_field_paths(infcx, upvar_tys, Struct::non_zero_field_paths(
tcx,
param_env,
upvar_tys,
Some(&variant.memory_index[..])) Some(&variant.memory_index[..]))
} }
// Can we use one of the fields in this tuple? // Can we use one of the fields in this tuple?
(&Univariant { ref variant, .. }, &ty::TyTuple(tys, _)) => { (&Univariant { ref variant, .. }, &ty::TyTuple(tys, _)) => {
Struct::non_zero_field_paths(infcx, tys.iter().cloned(), Struct::non_zero_field_paths(
tcx,
param_env,
tys.iter().cloned(),
Some(&variant.memory_index[..])) Some(&variant.memory_index[..]))
} }
// Is this a fixed-size array of something non-zero // Is this a fixed-size array of something non-zero
// with at least one element? // with at least one element?
(_, &ty::TyArray(ety, d)) if d > 0 => { (_, &ty::TyArray(ety, d)) if d > 0 => {
Struct::non_zero_field_paths(infcx, Some(ety).into_iter(), None) Struct::non_zero_field_paths(
tcx,
param_env,
Some(ety).into_iter(),
None)
} }
(_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => { (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => {
let normalized = infcx.normalize_projections(ty); let normalized = tcx.normalize_associated_type_in_env(&ty, param_env);
if ty == normalized { if ty == normalized {
return Ok(None); return Ok(None);
} }
return Struct::non_zero_field_in_type(infcx, normalized); return Struct::non_zero_field_in_type(tcx, param_env, normalized);
} }
// Anything else is not a non-zero type. // Anything else is not a non-zero type.
@ -838,13 +861,15 @@ impl<'a, 'gcx, 'tcx> Struct {
/// the given set of fields and recursing through aggregates. /// the given set of fields and recursing through aggregates.
/// Returns Some((path, source_path)) on success. /// Returns Some((path, source_path)) on success.
/// `path` is translated to memory order. `source_path` is not. /// `path` is translated to memory order. `source_path` is not.
fn non_zero_field_paths<I>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, fn non_zero_field_paths<I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
fields: I, param_env: ty::ParamEnv<'tcx>,
permutation: Option<&[u32]>) fields: I,
-> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>> permutation: Option<&[u32]>)
where I: Iterator<Item=Ty<'gcx>> { -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'tcx>>
where I: Iterator<Item=Ty<'tcx>> {
for (i, ty) in fields.enumerate() { for (i, ty) in fields.enumerate() {
if let Some((mut path, mut source_path)) = Struct::non_zero_field_in_type(infcx, ty)? { let r = Struct::non_zero_field_in_type(tcx, param_env, ty)?;
if let Some((mut path, mut source_path)) = r {
source_path.push(i as u32); source_path.push(i as u32);
let index = if let Some(p) = permutation { let index = if let Some(p) = permutation {
p[i] as usize p[i] as usize
@ -881,7 +906,7 @@ pub struct Union {
pub packed: bool, pub packed: bool,
} }
impl<'a, 'gcx, 'tcx> Union { impl<'a, 'tcx> Union {
fn new(dl: &TargetDataLayout, packed: bool) -> Union { fn new(dl: &TargetDataLayout, packed: bool) -> Union {
let align = if packed { dl.i8_align } else { dl.aggregate_align }; let align = if packed { dl.i8_align } else { dl.aggregate_align };
Union { Union {
@ -895,9 +920,9 @@ impl<'a, 'gcx, 'tcx> Union {
/// Extend the Struct with more fields. /// Extend the Struct with more fields.
fn extend<I>(&mut self, dl: &TargetDataLayout, fn extend<I>(&mut self, dl: &TargetDataLayout,
fields: I, fields: I,
scapegoat: Ty<'gcx>) scapegoat: Ty<'tcx>)
-> Result<(), LayoutError<'gcx>> -> Result<(), LayoutError<'tcx>>
where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> { where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {
for (index, field) in fields.enumerate() { for (index, field) in fields.enumerate() {
let field = field?; let field = field?;
if field.is_unsized() { if field.is_unsized() {
@ -1067,19 +1092,19 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
} }
} }
impl<'a, 'gcx, 'tcx> Layout { impl<'a, 'tcx> Layout {
pub fn compute_uncached(ty: Ty<'gcx>, pub fn compute_uncached(tcx: TyCtxt<'a, 'tcx, 'tcx>,
infcx: &InferCtxt<'a, 'gcx, 'tcx>) param_env: ty::ParamEnv<'tcx>,
-> Result<&'gcx Layout, LayoutError<'gcx>> { ty: Ty<'tcx>)
let tcx = infcx.tcx.global_tcx(); -> Result<&'tcx Layout, LayoutError<'tcx>> {
let success = |layout| Ok(tcx.intern_layout(layout)); let success = |layout| Ok(tcx.intern_layout(layout));
let dl = &tcx.data_layout; let dl = &tcx.data_layout;
assert!(!ty.has_infer_types()); assert!(!ty.has_infer_types());
let ptr_layout = |pointee: Ty<'gcx>| { let ptr_layout = |pointee: Ty<'tcx>| {
let non_zero = !ty.is_unsafe_ptr(); let non_zero = !ty.is_unsafe_ptr();
let pointee = infcx.normalize_projections(pointee); let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env);
if pointee.is_sized(tcx, infcx.param_env, DUMMY_SP) { if pointee.is_sized(tcx, param_env, DUMMY_SP) {
Ok(Scalar { value: Pointer, non_zero: non_zero }) Ok(Scalar { value: Pointer, non_zero: non_zero })
} else { } else {
let unsized_part = tcx.struct_tail(pointee); let unsized_part = tcx.struct_tail(pointee);
@ -1132,7 +1157,7 @@ impl<'a, 'gcx, 'tcx> Layout {
// Arrays and slices. // Arrays and slices.
ty::TyArray(element, count) => { ty::TyArray(element, count) => {
let element = element.layout(infcx)?; let element = element.layout(tcx, param_env)?;
let element_size = element.size(dl); let element_size = element.size(dl);
// FIXME(eddyb) Don't use host `usize` for array lengths. // FIXME(eddyb) Don't use host `usize` for array lengths.
let usize_count: usize = count; let usize_count: usize = count;
@ -1149,7 +1174,7 @@ impl<'a, 'gcx, 'tcx> Layout {
} }
} }
ty::TySlice(element) => { ty::TySlice(element) => {
let element = element.layout(infcx)?; let element = element.layout(tcx, param_env)?;
Array { Array {
sized: false, sized: false,
align: element.align(dl), align: element.align(dl),
@ -1187,7 +1212,7 @@ impl<'a, 'gcx, 'tcx> Layout {
ty::TyClosure(def_id, ref substs) => { ty::TyClosure(def_id, ref substs) => {
let tys = substs.upvar_tys(def_id, tcx); let tys = substs.upvar_tys(def_id, tcx);
let st = Struct::new(dl, let st = Struct::new(dl,
&tys.map(|ty| ty.layout(infcx)) &tys.map(|ty| ty.layout(tcx, param_env))
.collect::<Result<Vec<_>, _>>()?, .collect::<Result<Vec<_>, _>>()?,
&ReprOptions::default(), &ReprOptions::default(),
StructKind::AlwaysSizedUnivariant, ty)?; StructKind::AlwaysSizedUnivariant, ty)?;
@ -1198,7 +1223,7 @@ impl<'a, 'gcx, 'tcx> Layout {
// FIXME(camlorn): if we ever allow unsized tuples, this needs to be checked. // FIXME(camlorn): if we ever allow unsized tuples, this needs to be checked.
// See the univariant case below to learn how. // See the univariant case below to learn how.
let st = Struct::new(dl, let st = Struct::new(dl,
&tys.iter().map(|ty| ty.layout(infcx)) &tys.iter().map(|ty| ty.layout(tcx, param_env))
.collect::<Result<Vec<_>, _>>()?, .collect::<Result<Vec<_>, _>>()?,
&ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?; &ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?;
Univariant { variant: st, non_zero: false } Univariant { variant: st, non_zero: false }
@ -1207,7 +1232,7 @@ impl<'a, 'gcx, 'tcx> Layout {
// SIMD vector types. // SIMD vector types.
ty::TyAdt(def, ..) if def.repr.simd() => { ty::TyAdt(def, ..) if def.repr.simd() => {
let element = ty.simd_type(tcx); let element = ty.simd_type(tcx);
match *element.layout(infcx)? { match *element.layout(tcx, param_env)? {
Scalar { value, .. } => { Scalar { value, .. } => {
return success(Vector { return success(Vector {
element: value, element: value,
@ -1278,7 +1303,7 @@ impl<'a, 'gcx, 'tcx> Layout {
}; };
let fields = def.variants[0].fields.iter().map(|field| { let fields = def.variants[0].fields.iter().map(|field| {
field.ty(tcx, substs).layout(infcx) field.ty(tcx, substs).layout(tcx, param_env)
}).collect::<Result<Vec<_>, _>>()?; }).collect::<Result<Vec<_>, _>>()?;
let layout = if def.is_union() { let layout = if def.is_union() {
let mut un = Union::new(dl, def.repr.packed()); let mut un = Union::new(dl, def.repr.packed());
@ -1312,20 +1337,21 @@ impl<'a, 'gcx, 'tcx> Layout {
// Nullable pointer optimization // Nullable pointer optimization
for discr in 0..2 { for discr in 0..2 {
let other_fields = variants[1 - discr].iter().map(|ty| { let other_fields = variants[1 - discr].iter().map(|ty| {
ty.layout(infcx) ty.layout(tcx, param_env)
}); });
if !Struct::would_be_zero_sized(dl, other_fields)? { if !Struct::would_be_zero_sized(dl, other_fields)? {
continue; continue;
} }
let paths = Struct::non_zero_field_paths(infcx, let paths = Struct::non_zero_field_paths(tcx,
variants[discr].iter().cloned(), param_env,
None)?; variants[discr].iter().cloned(),
None)?;
let (mut path, mut path_source) = if let Some(p) = paths { p } let (mut path, mut path_source) = if let Some(p) = paths { p }
else { continue }; else { continue };
// FIXME(eddyb) should take advantage of a newtype. // FIXME(eddyb) should take advantage of a newtype.
if path == &[0] && variants[discr].len() == 1 { if path == &[0] && variants[discr].len() == 1 {
let value = match *variants[discr][0].layout(infcx)? { let value = match *variants[discr][0].layout(tcx, param_env)? {
Scalar { value, .. } => value, Scalar { value, .. } => value,
CEnum { discr, .. } => Int(discr), CEnum { discr, .. } => Int(discr),
_ => bug!("Layout::compute: `{}`'s non-zero \ _ => bug!("Layout::compute: `{}`'s non-zero \
@ -1339,7 +1365,7 @@ impl<'a, 'gcx, 'tcx> Layout {
} }
let st = Struct::new(dl, let st = Struct::new(dl,
&variants[discr].iter().map(|ty| ty.layout(infcx)) &variants[discr].iter().map(|ty| ty.layout(tcx, param_env))
.collect::<Result<Vec<_>, _>>()?, .collect::<Result<Vec<_>, _>>()?,
&def.repr, StructKind::AlwaysSizedUnivariant, ty)?; &def.repr, StructKind::AlwaysSizedUnivariant, ty)?;
@ -1377,7 +1403,7 @@ impl<'a, 'gcx, 'tcx> Layout {
let discr = Scalar { value: Int(min_ity), non_zero: false }; let discr = Scalar { value: Int(min_ity), non_zero: false };
let mut variants = variants.into_iter().map(|fields| { let mut variants = variants.into_iter().map(|fields| {
let mut fields = fields.into_iter().map(|field| { let mut fields = fields.into_iter().map(|field| {
field.layout(infcx) field.layout(tcx, param_env)
}).collect::<Result<Vec<_>, _>>()?; }).collect::<Result<Vec<_>, _>>()?;
fields.insert(0, &discr); fields.insert(0, &discr);
let st = Struct::new(dl, let st = Struct::new(dl,
@ -1470,11 +1496,11 @@ impl<'a, 'gcx, 'tcx> Layout {
// Types with no meaningful known layout. // Types with no meaningful known layout.
ty::TyProjection(_) | ty::TyAnon(..) => { ty::TyProjection(_) | ty::TyAnon(..) => {
let normalized = infcx.normalize_projections(ty); let normalized = tcx.normalize_associated_type_in_env(&ty, param_env);
if ty == normalized { if ty == normalized {
return Err(LayoutError::Unknown(ty)); return Err(LayoutError::Unknown(ty));
} }
return normalized.layout(infcx); return normalized.layout(tcx, param_env);
} }
ty::TyParam(_) => { ty::TyParam(_) => {
return Err(LayoutError::Unknown(ty)); return Err(LayoutError::Unknown(ty));
@ -1686,21 +1712,22 @@ pub enum SizeSkeleton<'tcx> {
} }
} }
impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { impl<'a, 'tcx> SizeSkeleton<'tcx> {
pub fn compute(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>) pub fn compute(ty: Ty<'tcx>,
-> Result<SizeSkeleton<'gcx>, LayoutError<'gcx>> { tcx: TyCtxt<'a, 'tcx, 'tcx>,
let tcx = infcx.tcx.global_tcx(); param_env: ty::ParamEnv<'tcx>)
-> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> {
assert!(!ty.has_infer_types()); assert!(!ty.has_infer_types());
// First try computing a static layout. // First try computing a static layout.
let err = match ty.layout(infcx) { let err = match ty.layout(tcx, param_env) {
Ok(layout) => { Ok(layout) => {
return Ok(SizeSkeleton::Known(layout.size(tcx))); return Ok(SizeSkeleton::Known(layout.size(tcx)));
} }
Err(err) => err Err(err) => err
}; };
let ptr_skeleton = |pointee: Ty<'gcx>| { let ptr_skeleton = |pointee: Ty<'tcx>| {
let non_zero = !ty.is_unsafe_ptr(); let non_zero = !ty.is_unsafe_ptr();
let tail = tcx.struct_tail(pointee); let tail = tcx.struct_tail(pointee);
match tail.sty { match tail.sty {
@ -1737,7 +1764,7 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
// Get a zero-sized variant or a pointer newtype. // Get a zero-sized variant or a pointer newtype.
let zero_or_ptr_variant = |i: usize| { let zero_or_ptr_variant = |i: usize| {
let fields = def.variants[i].fields.iter().map(|field| { let fields = def.variants[i].fields.iter().map(|field| {
SizeSkeleton::compute(field.ty(tcx, substs), infcx) SizeSkeleton::compute(field.ty(tcx, substs), tcx, param_env)
}); });
let mut ptr = None; let mut ptr = None;
for field in fields { for field in fields {
@ -1788,11 +1815,11 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
} }
ty::TyProjection(_) | ty::TyAnon(..) => { ty::TyProjection(_) | ty::TyAnon(..) => {
let normalized = infcx.normalize_projections(ty); let normalized = tcx.normalize_associated_type_in_env(&ty, param_env);
if ty == normalized { if ty == normalized {
Err(err) Err(err)
} else { } else {
SizeSkeleton::compute(normalized, infcx) SizeSkeleton::compute(normalized, tcx, param_env)
} }
} }
@ -1826,71 +1853,53 @@ impl<'tcx> Deref for TyLayout<'tcx> {
} }
} }
pub trait HasTyCtxt<'tcx>: HasDataLayout { pub trait LayoutTyper<'tcx>: HasDataLayout {
type TyLayout;
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>; fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout;
fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>;
} }
impl<'a, 'gcx, 'tcx> HasDataLayout for TyCtxt<'a, 'gcx, 'tcx> { /// Combines a tcx with the parameter environment so that you can
fn data_layout(&self) -> &TargetDataLayout { /// compute layout operations.
&self.data_layout #[derive(Copy, Clone)]
pub struct LayoutCx<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
}
impl<'a, 'tcx> LayoutCx<'a, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
LayoutCx { tcx, param_env }
} }
} }
impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> { impl<'a, 'tcx> HasDataLayout for LayoutCx<'a, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
self.global_tcx()
}
}
impl<'a, 'gcx, 'tcx> HasDataLayout for &'a InferCtxt<'a, 'gcx, 'tcx> {
fn data_layout(&self) -> &TargetDataLayout { fn data_layout(&self) -> &TargetDataLayout {
&self.tcx.data_layout &self.tcx.data_layout
} }
} }
impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> { impl<'a, 'tcx> LayoutTyper<'tcx> for LayoutCx<'a, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> { type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
self.tcx.global_tcx()
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
self.tcx
} }
}
pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> { fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
type TyLayout;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout;
fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>;
}
impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
type TyLayout = Result<TyLayout<'gcx>, LayoutError<'gcx>>;
fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout {
let ty = self.normalize_projections(ty); let ty = self.normalize_projections(ty);
Ok(TyLayout { Ok(TyLayout {
ty: ty, ty: ty,
layout: ty.layout(self)?, layout: ty.layout(self.tcx, self.param_env)?,
variant_index: None variant_index: None
}) })
} }
fn normalize_projections(self, ty: Ty<'gcx>) -> Ty<'gcx> { fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> {
if !ty.has_projection_types() { self.tcx.normalize_associated_type_in_env(&ty, self.param_env)
return ty;
}
let mut selcx = traits::SelectionContext::new(self);
let cause = traits::ObligationCause::dummy();
let traits::Normalized { value: result, obligations } =
traits::normalize(&mut selcx, cause, &ty);
let mut fulfill_cx = traits::FulfillmentContext::new();
for obligation in obligations {
fulfill_cx.register_predicate_obligation(self, obligation);
}
self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
} }
} }
@ -1943,7 +1952,7 @@ impl<'a, 'tcx> TyLayout<'tcx> {
} }
} }
pub fn field_type<C: HasTyCtxt<'tcx>>(&self, cx: C, i: usize) -> Ty<'tcx> { pub fn field_type<C: LayoutTyper<'tcx>>(&self, cx: C, i: usize) -> Ty<'tcx> {
let tcx = cx.tcx(); let tcx = cx.tcx();
let ptr_field_type = |pointee: Ty<'tcx>| { let ptr_field_type = |pointee: Ty<'tcx>| {
@ -2014,7 +2023,10 @@ impl<'a, 'tcx> TyLayout<'tcx> {
} }
} }
pub fn field<C: LayoutTyper<'tcx>>(&self, cx: C, i: usize) -> C::TyLayout { pub fn field<C: LayoutTyper<'tcx>>(&self,
cx: C,
i: usize)
-> C::TyLayout {
cx.layout_of(cx.normalize_projections(self.field_type(cx, i))) cx.layout_of(cx.normalize_projections(self.field_type(cx, i)))
} }
} }

View File

@ -20,6 +20,7 @@ use mir::transform::{MirSuite, MirPassIndex};
use session::CompileResult; use session::CompileResult;
use traits::specialization_graph; use traits::specialization_graph;
use ty::{self, CrateInherentImpls, Ty, TyCtxt}; use ty::{self, CrateInherentImpls, Ty, TyCtxt};
use ty::layout::{Layout, LayoutError};
use ty::item_path; use ty::item_path;
use ty::steal::Steal; use ty::steal::Steal;
use ty::subst::Substs; use ty::subst::Substs;
@ -293,6 +294,12 @@ impl<'tcx> QueryDescription for queries::needs_drop_raw<'tcx> {
} }
} }
impl<'tcx> QueryDescription for queries::layout_raw<'tcx> {
fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
format!("computing layout of `{}`", env.value)
}
}
impl<'tcx> QueryDescription for queries::super_predicates_of<'tcx> { impl<'tcx> QueryDescription for queries::super_predicates_of<'tcx> {
fn describe(tcx: TyCtxt, def_id: DefId) -> String { fn describe(tcx: TyCtxt, def_id: DefId) -> String {
format!("computing the supertraits of `{}`", format!("computing the supertraits of `{}`",
@ -920,6 +927,8 @@ define_maps! { <'tcx>
[] is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
[] is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
[] needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
[] layout_raw: layout_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
-> Result<&'tcx Layout, LayoutError<'tcx>>,
} }
fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> { fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
@ -987,3 +996,9 @@ fn needs_drop_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode<De
.unwrap_or(DefId::local(CRATE_DEF_INDEX)); .unwrap_or(DefId::local(CRATE_DEF_INDEX));
DepNode::NeedsDrop(def_id) DepNode::NeedsDrop(def_id)
} }
fn layout_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode<DefId> {
let def_id = ty::item_path::characteristic_def_id_of_type(key.value)
.unwrap_or(DefId::local(CRATE_DEF_INDEX));
DepNode::Layout(def_id)
}

View File

@ -12,7 +12,6 @@
use hir::def_id::{DefId, LOCAL_CRATE}; use hir::def_id::{DefId, LOCAL_CRATE};
use hir::map::DefPathData; use hir::map::DefPathData;
use infer::InferCtxt;
use ich::{StableHashingContext, NodeIdHashingMode}; use ich::{StableHashingContext, NodeIdHashingMode};
use traits::{self, Reveal}; use traits::{self, Reveal};
use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::{self, Ty, TyCtxt, TypeFoldable};
@ -791,35 +790,17 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
tcx.needs_drop_raw(param_env.and(self)) tcx.needs_drop_raw(param_env.and(self))
} }
/// Computes the layout of a type. Note that this implicitly
/// executes in "reveal all" mode.
#[inline] #[inline]
pub fn layout<'lcx>(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'lcx>) pub fn layout<'lcx>(&'tcx self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>)
-> Result<&'tcx Layout, LayoutError<'tcx>> { -> Result<&'tcx Layout, LayoutError<'tcx>> {
let tcx = infcx.tcx.global_tcx(); let ty = tcx.erase_regions(&self);
let can_cache = !self.has_param_types() && !self.has_self_ty(); tcx.layout_raw(param_env.reveal_all().and(ty))
if can_cache {
if let Some(&cached) = tcx.layout_cache.borrow().get(&self) {
return Ok(cached);
}
}
let rec_limit = tcx.sess.recursion_limit.get();
let depth = tcx.layout_depth.get();
if depth > rec_limit {
tcx.sess.fatal(
&format!("overflow representing the type `{}`", self));
}
tcx.layout_depth.set(depth+1);
let layout = Layout::compute_uncached(self, infcx);
tcx.layout_depth.set(depth);
let layout = layout?;
if can_cache {
tcx.layout_cache.borrow_mut().insert(self, layout);
}
Ok(layout)
} }
/// Check whether a type is representable. This means it cannot contain unboxed /// Check whether a type is representable. This means it cannot contain unboxed
/// structural recursion. This check is needed for structs and enums. /// structural recursion. This check is needed for structs and enums.
pub fn is_representable(&'tcx self, pub fn is_representable(&'tcx self,
@ -1074,6 +1055,24 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
} }
} }
fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
-> Result<&'tcx Layout, LayoutError<'tcx>>
{
let (param_env, ty) = query.into_parts();
let rec_limit = tcx.sess.recursion_limit.get();
let depth = tcx.layout_depth.get();
if depth > rec_limit {
tcx.sess.fatal(
&format!("overflow representing the type `{}`", ty));
}
tcx.layout_depth.set(depth+1);
let layout = Layout::compute_uncached(tcx, param_env, ty);
tcx.layout_depth.set(depth);
layout
}
pub fn provide(providers: &mut ty::maps::Providers) { pub fn provide(providers: &mut ty::maps::Providers) {
*providers = ty::maps::Providers { *providers = ty::maps::Providers {
@ -1081,6 +1080,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
is_sized_raw, is_sized_raw,
is_freeze_raw, is_freeze_raw,
needs_drop_raw, needs_drop_raw,
layout_raw,
..*providers ..*providers
}; };
} }

View File

@ -14,7 +14,6 @@ use rustc::hir::def_id::DefId;
use rustc::ty::subst::Substs; use rustc::ty::subst::Substs;
use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::{self, AdtKind, Ty, TyCtxt};
use rustc::ty::layout::{Layout, Primitive}; use rustc::ty::layout::{Layout, Primitive};
use rustc::traits::Reveal;
use middle::const_val::ConstVal; use middle::const_val::ConstVal;
use rustc_const_eval::ConstContext; use rustc_const_eval::ConstContext;
use util::nodemap::FxHashSet; use util::nodemap::FxHashSet;
@ -724,12 +723,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
if let hir::ItemEnum(ref enum_definition, ref gens) = it.node { if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
if gens.ty_params.is_empty() { if gens.ty_params.is_empty() {
// sizes only make sense for non-generic types // sizes only make sense for non-generic types
let t = cx.tcx.type_of(cx.tcx.hir.local_def_id(it.id)); let item_def_id = cx.tcx.hir.local_def_id(it.id);
let layout = cx.tcx.infer_ctxt(Reveal::All).enter(|infcx| { let t = cx.tcx.type_of(item_def_id);
let ty = cx.tcx.erase_regions(&t); let param_env = cx.tcx.param_env(item_def_id).reveal_all();
ty.layout(&infcx).unwrap_or_else(|e| { let ty = cx.tcx.erase_regions(&t);
bug!("failed to get layout for `{}`: {}", t, e) let layout = ty.layout(cx.tcx, param_env).unwrap_or_else(|e| {
}) bug!("failed to get layout for `{}`: {}", t, e)
}); });
if let Layout::General { ref variants, ref size, discr, .. } = *layout { if let Layout::General { ref variants, ref size, discr, .. } = *layout {

View File

@ -547,10 +547,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>) -> Option<u64> { ty: Ty<'tcx>) -> Option<u64> {
tcx.infer_ctxt(param_env.reveal_all()).enter(|infcx| { ty.layout(tcx, param_env).ok().map(|layout| {
ty.layout(&infcx).ok().map(|layout| { layout.size(&tcx.data_layout).bytes()
layout.size(&tcx.data_layout).bytes()
})
}) })
} }

View File

@ -25,10 +25,10 @@ use type_::Type;
use rustc_data_structures::base_n; use rustc_data_structures::base_n;
use rustc::ty::subst::Substs; use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::{LayoutTyper, TyLayout}; use rustc::ty::layout::{LayoutCx, LayoutError, LayoutTyper, TyLayout};
use rustc::session::config::{self, NoDebugInfo}; use session::config::{self, NoDebugInfo};
use rustc::session::Session; use session::Session;
use rustc::util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
@ -709,41 +709,27 @@ impl<'a, 'tcx> ty::layout::HasDataLayout for &'a SharedCrateContext<'a, 'tcx> {
} }
} }
impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
self.tcx
}
}
impl<'a, 'tcx> ty::layout::HasDataLayout for &'a CrateContext<'a, 'tcx> { impl<'a, 'tcx> ty::layout::HasDataLayout for &'a CrateContext<'a, 'tcx> {
fn data_layout(&self) -> &ty::layout::TargetDataLayout { fn data_layout(&self) -> &ty::layout::TargetDataLayout {
&self.shared.tcx.data_layout &self.shared.tcx.data_layout
} }
} }
impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a CrateContext<'a, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
self.shared.tcx
}
}
impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> { impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
type TyLayout = TyLayout<'tcx>; type TyLayout = TyLayout<'tcx>;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
if let Some(&layout) = self.tcx().layout_cache.borrow().get(&ty) { self.tcx
return TyLayout { ty: ty, layout: layout, variant_index: None }; }
}
self.tcx().infer_ctxt(traits::Reveal::All).enter(|infcx| { fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
infcx.layout_of(ty).unwrap_or_else(|e| { let param_env = ty::ParamEnv::empty(traits::Reveal::All);
match e { LayoutCx::new(self.tcx, param_env)
ty::layout::LayoutError::SizeOverflow(_) => .layout_of(ty)
self.sess().fatal(&e.to_string()), .unwrap_or_else(|e| match e {
_ => bug!("failed to get layout for `{}`: {}", ty, e) LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()),
} _ => bug!("failed to get layout for `{}`: {}", ty, e)
}) })
})
} }
fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> { fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> {
@ -754,6 +740,10 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> { impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> {
type TyLayout = TyLayout<'tcx>; type TyLayout = TyLayout<'tcx>;
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
self.shared.tcx
}
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
self.shared.layout_of(ty) self.shared.layout_of(ty)
} }

View File

@ -46,15 +46,13 @@ pub fn needs_drop_glue<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'tcx>
ty::TyAdt(def, _) if def.is_box() => { ty::TyAdt(def, _) if def.is_box() => {
let typ = t.boxed_ty(); let typ = t.boxed_ty();
if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) { if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) {
scx.tcx().infer_ctxt(traits::Reveal::All).enter(|infcx| { let layout = t.layout(scx.tcx(), ty::ParamEnv::empty(traits::Reveal::All)).unwrap();
let layout = t.layout(&infcx).unwrap(); if layout.size(scx).bytes() == 0 {
if layout.size(scx).bytes() == 0 { // `Box<ZeroSizeType>` does not allocate.
// `Box<ZeroSizeType>` does not allocate. false
false } else {
} else { true
true }
}
})
} else { } else {
true true
} }