about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2017-05-19 17:27:25 -0400
committerNiko Matsakis <niko@alum.mit.edu>2017-06-01 12:56:30 -0400
commit541523d10dce98dc266f6d4e6fb6131182c0f791 (patch)
tree8a9f72b4e0c7d4e1ec48d65440016fac921337a0
parent6c4b961effdbec1bb2fc5aaed5aeb219eb7f3b19 (diff)
rewrite layout to take a (param-env, ty) pair instead of infcx
-rw-r--r--src/librustc/dep_graph/dep_node.rs2
-rw-r--r--src/librustc/middle/intrinsicck.rs51
-rw-r--r--src/librustc/ty/layout.rs236
-rw-r--r--src/librustc/ty/maps.rs15
-rw-r--r--src/librustc/ty/util.rs52
-rw-r--r--src/librustc_lint/types.rs13
-rw-r--r--src/librustc_mir/transform/inline.rs6
-rw-r--r--src/librustc_trans/context.rs46
-rw-r--r--src/librustc_trans/glue.rs16
9 files changed, 225 insertions, 212 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 38ad473e404..c38b3745f4c 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -112,6 +112,7 @@ pub enum DepNode<D: Clone + Debug> {
     IsSized(D),
     IsFreeze(D),
     NeedsDrop(D),
+    Layout(D),
 
     // The set of impls for a given trait. Ultimately, it would be
     // 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),
             IsFreeze(ref d) => op(d).map(IsFreeze),
             NeedsDrop(ref d) => op(d).map(NeedsDrop),
+            Layout(ref d) => op(d).map(Layout),
             Hir(ref d) => op(d).map(Hir),
             HirBody(ref d) => op(d).map(HirBody),
             MetaData(ref d) => op(d).map(MetaData),
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index 08f731ae34d..57815b7f0b6 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -10,7 +10,6 @@
 
 use hir::def::Def;
 use hir::def_id::DefId;
-use infer::InferCtxt;
 use ty::{self, Ty, TyCtxt};
 use ty::layout::{LayoutError, Pointer, SizeSkeleton};
 
@@ -30,8 +29,10 @@ struct ItemVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>
 }
 
-struct ExprVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>
+struct ExprVisitor<'a, 'tcx: 'a> {
+    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
@@ -63,18 +64,18 @@ fn unpack_option_like<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     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 {
-        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,
             _ => 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>) {
-        let sk_from = SizeSkeleton::compute(from, self.infcx);
-        let sk_to = SizeSkeleton::compute(to, self.infcx);
+    fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) {
+        let sk_from = SizeSkeleton::compute(from, self.tcx, self.param_env);
+        let sk_to = SizeSkeleton::compute(to, self.tcx, self.param_env);
 
         // Check for same size using the skeletons.
         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
             // `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) {
                 (&ty::TyFnDef(..), SizeSkeleton::Known(size_to))
-                        if size_to == Pointer.size(self.infcx) => {
-                    struct_span_err!(self.infcx.tcx.sess, span, E0591,
+                        if size_to == Pointer.size(self.tcx) => {
+                    struct_span_err!(self.tcx.sess, span, E0591,
                                      "`{}` is zero-sized and can't be transmuted to `{}`",
                                      from, to)
                         .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.
-        let skeleton_string = |ty: Ty<'gcx>, sk| {
+        let skeleton_string = |ty: Ty<'tcx>, sk| {
             match sk {
                 Ok(SizeSkeleton::Known(size)) => {
                     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: \
                    {} ({}) to {} ({})",
                   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) {
+        let owner_def_id = self.tcx.hir.body_owner_def_id(body_id);
         let body = self.tcx.hir.body(body_id);
-        self.tcx.infer_ctxt(body_id).enter(|infcx| {
-            let mut visitor = ExprVisitor {
-                infcx: &infcx
-            };
-            visitor.visit_body(body);
-        });
+        let param_env = self.tcx.param_env(owner_def_id);
+        let tables = self.tcx.typeck_tables_of(owner_def_id);
+        ExprVisitor { tcx: self.tcx, param_env, tables }.visit_body(body);
         self.visit_body(body);
     }
 }
 
-impl<'a, 'gcx, 'tcx> Visitor<'gcx> for ExprVisitor<'a, 'gcx, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
+impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
         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 {
-            self.infcx.tables.borrow().qpath_def(qpath, expr.id)
+            self.tables.qpath_def(qpath, expr.id)
         } else {
             Def::Err
         };
         match def {
             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.infcx.tcx.lift_to_global(&typ).unwrap();
+                let typ = self.tables.node_id_to_type(expr.id);
+                let typ = self.tcx.lift_to_global(&typ).unwrap();
                 match typ.sty {
                     ty::TyFnDef(.., sig) if sig.abi() == RustIntrinsic => {
                         let from = sig.inputs().skip_binder()[0];
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 1a8c74ff1f9..4dc764f6d30 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -12,9 +12,7 @@ pub use self::Integer::*;
 pub use self::Layout::*;
 pub use self::Primitive::*;
 
-use infer::InferCtxt;
 use session::Session;
-use traits;
 use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, ReprFlags};
 
 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).
 #[derive(Copy, Clone)]
 pub enum Endian {
@@ -457,8 +461,12 @@ impl Integer {
     /// signed discriminant range and #[repr] attribute.
     /// N.B.: u64 values above i64::MAX will be treated as signed, but
     /// that shouldn't affect anything, other than maybe debuginfo.
-    fn repr_discr(tcx: TyCtxt, ty: Ty, repr: &ReprOptions, min: i64, max: i64)
-                      -> (Integer, bool) {
+    fn repr_discr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                            ty: Ty<'tcx>,
+                            repr: &ReprOptions,
+                            min: i64,
+                            max: i64)
+                            -> (Integer, bool) {
         // Theoretically, negative values could be larger in unsigned representation
         // than the unsigned representation of the signed minimum. However, if there
         // are any negative values, the only valid unsigned representation is u64
@@ -583,10 +591,13 @@ enum StructKind {
     EnumVariant,
 }
 
-impl<'a, 'gcx, 'tcx> Struct {
-    fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
-                  repr: &ReprOptions, kind: StructKind,
-                  scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
+impl<'a, 'tcx> Struct {
+    fn new(dl: &TargetDataLayout,
+           fields: &Vec<&'a Layout>,
+           repr: &ReprOptions,
+           kind: StructKind,
+           scapegoat: Ty<'tcx>)
+           -> Result<Struct, LayoutError<'tcx>> {
         if repr.packed() && repr.align > 0 {
             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.
     fn would_be_zero_sized<I>(dl: &TargetDataLayout, fields: I)
-                              -> Result<bool, LayoutError<'gcx>>
-    where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
+                              -> Result<bool, LayoutError<'tcx>>
+    where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {
         for field in fields {
             let field = field?;
             if field.is_unsized() || field.size(dl).bytes() > 0 {
@@ -764,11 +775,11 @@ impl<'a, 'gcx, 'tcx> Struct {
     /// The tuple is `(path, source_path)`,
     /// where `path` is in memory order and `source_path` in source order.
     // FIXME(eddyb) track value ranges and traverse already optimized enums.
-    fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                               ty: Ty<'gcx>)
-                               -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>> {
-        let tcx = infcx.tcx.global_tcx();
-        match (ty.layout(infcx)?, &ty.sty) {
+    fn non_zero_field_in_type(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                              param_env: ty::ParamEnv<'tcx>,
+                              ty: Ty<'tcx>)
+                              -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'tcx>> {
+        match (ty.layout(tcx, param_env)?, &ty.sty) {
             (&Scalar { non_zero: true, .. }, _) |
             (&CEnum { non_zero: true, .. }, _) => Ok(Some((vec![], vec![]))),
             (&FatPointer { non_zero: true, .. }, _) => {
@@ -779,7 +790,7 @@ impl<'a, 'gcx, 'tcx> Struct {
             (&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) => {
                 let fields = &def.struct_variant().fields;
                 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.
                     Scalar { value: Int(_), 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
             // let's recurse and find out
             (&Univariant { ref variant, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => {
-                Struct::non_zero_field_paths(infcx, def.struct_variant().fields
-                                                      .iter().map(|field| {
-                    field.ty(tcx, substs)
-                }),
-                Some(&variant.memory_index[..]))
+                Struct::non_zero_field_paths(
+                    tcx,
+                    param_env,
+                    def.struct_variant().fields.iter().map(|field| {
+                        field.ty(tcx, substs)
+                    }),
+                    Some(&variant.memory_index[..]))
             }
 
             // Perhaps one of the upvars of this closure is non-zero
             (&Univariant { ref variant, .. }, &ty::TyClosure(def, substs)) => {
                 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[..]))
             }
             // Can we use one of the fields in this tuple?
             (&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[..]))
             }
 
             // Is this a fixed-size array of something non-zero
             // with at least one element?
             (_, &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(..)) => {
-                let normalized = infcx.normalize_projections(ty);
+                let normalized = tcx.normalize_associated_type_in_env(&ty, param_env);
                 if ty == normalized {
                     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.
@@ -838,13 +861,15 @@ impl<'a, 'gcx, 'tcx> Struct {
     /// the given set of fields and recursing through aggregates.
     /// Returns Some((path, source_path)) on success.
     /// `path` is translated to memory order. `source_path` is not.
-    fn non_zero_field_paths<I>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                  fields: I,
-                                  permutation: Option<&[u32]>)
-                                  -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>>
-    where I: Iterator<Item=Ty<'gcx>> {
+    fn non_zero_field_paths<I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                               param_env: ty::ParamEnv<'tcx>,
+                               fields: I,
+                               permutation: Option<&[u32]>)
+                               -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'tcx>>
+    where I: Iterator<Item=Ty<'tcx>> {
         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);
                 let index = if let Some(p) = permutation {
                     p[i] as usize
@@ -881,7 +906,7 @@ pub struct Union {
     pub packed: bool,
 }
 
-impl<'a, 'gcx, 'tcx> Union {
+impl<'a, 'tcx> Union {
     fn new(dl: &TargetDataLayout, packed: bool) -> Union {
         let align = if packed { dl.i8_align } else { dl.aggregate_align };
         Union {
@@ -895,9 +920,9 @@ impl<'a, 'gcx, 'tcx> Union {
     /// Extend the Struct with more fields.
     fn extend<I>(&mut self, dl: &TargetDataLayout,
                  fields: I,
-                 scapegoat: Ty<'gcx>)
-                 -> Result<(), LayoutError<'gcx>>
-    where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
+                 scapegoat: Ty<'tcx>)
+                 -> Result<(), LayoutError<'tcx>>
+    where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {
         for (index, field) in fields.enumerate() {
             let field = field?;
             if field.is_unsized() {
@@ -1067,19 +1092,19 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx> Layout {
-    pub fn compute_uncached(ty: Ty<'gcx>,
-                            infcx: &InferCtxt<'a, 'gcx, 'tcx>)
-                            -> Result<&'gcx Layout, LayoutError<'gcx>> {
-        let tcx = infcx.tcx.global_tcx();
+impl<'a, 'tcx> Layout {
+    pub fn compute_uncached(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                            param_env: ty::ParamEnv<'tcx>,
+                            ty: Ty<'tcx>)
+                            -> Result<&'tcx Layout, LayoutError<'tcx>> {
         let success = |layout| Ok(tcx.intern_layout(layout));
         let dl = &tcx.data_layout;
         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 pointee = infcx.normalize_projections(pointee);
-            if pointee.is_sized(tcx, infcx.param_env, DUMMY_SP) {
+            let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env);
+            if pointee.is_sized(tcx, param_env, DUMMY_SP) {
                 Ok(Scalar { value: Pointer, non_zero: non_zero })
             } else {
                 let unsized_part = tcx.struct_tail(pointee);
@@ -1132,7 +1157,7 @@ impl<'a, 'gcx, 'tcx> Layout {
 
             // Arrays and slices.
             ty::TyArray(element, count) => {
-                let element = element.layout(infcx)?;
+                let element = element.layout(tcx, param_env)?;
                 let element_size = element.size(dl);
                 // FIXME(eddyb) Don't use host `usize` for array lengths.
                 let usize_count: usize = count;
@@ -1149,7 +1174,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                 }
             }
             ty::TySlice(element) => {
-                let element = element.layout(infcx)?;
+                let element = element.layout(tcx, param_env)?;
                 Array {
                     sized: false,
                     align: element.align(dl),
@@ -1187,7 +1212,7 @@ impl<'a, 'gcx, 'tcx> Layout {
             ty::TyClosure(def_id, ref substs) => {
                 let tys = substs.upvar_tys(def_id, tcx);
                 let st = Struct::new(dl,
-                    &tys.map(|ty| ty.layout(infcx))
+                    &tys.map(|ty| ty.layout(tcx, param_env))
                       .collect::<Result<Vec<_>, _>>()?,
                     &ReprOptions::default(),
                     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.
                 // See the univariant case below to learn how.
                 let st = Struct::new(dl,
-                    &tys.iter().map(|ty| ty.layout(infcx))
+                    &tys.iter().map(|ty| ty.layout(tcx, param_env))
                       .collect::<Result<Vec<_>, _>>()?,
                     &ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?;
                 Univariant { variant: st, non_zero: false }
@@ -1207,7 +1232,7 @@ impl<'a, 'gcx, 'tcx> Layout {
             // SIMD vector types.
             ty::TyAdt(def, ..) if def.repr.simd() => {
                 let element = ty.simd_type(tcx);
-                match *element.layout(infcx)? {
+                match *element.layout(tcx, param_env)? {
                     Scalar { value, .. } => {
                         return success(Vector {
                             element: value,
@@ -1278,7 +1303,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                     };
 
                     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<_>, _>>()?;
                     let layout = if def.is_union() {
                         let mut un = Union::new(dl, def.repr.packed());
@@ -1312,20 +1337,21 @@ impl<'a, 'gcx, 'tcx> Layout {
                     // Nullable pointer optimization
                     for discr in 0..2 {
                         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)? {
                             continue;
                         }
-                        let paths = Struct::non_zero_field_paths(infcx,
-                            variants[discr].iter().cloned(),
-                            None)?;
+                        let paths = Struct::non_zero_field_paths(tcx,
+                                                                 param_env,
+                                                                 variants[discr].iter().cloned(),
+                                                                 None)?;
                         let (mut path, mut path_source) = if let Some(p) = paths { p }
                           else { continue };
 
                         // FIXME(eddyb) should take advantage of a newtype.
                         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,
                                 CEnum { discr, .. } => Int(discr),
                                 _ => bug!("Layout::compute: `{}`'s non-zero \
@@ -1339,7 +1365,7 @@ impl<'a, 'gcx, 'tcx> Layout {
                         }
 
                         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<_>, _>>()?,
                             &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 mut variants = variants.into_iter().map(|fields| {
                     let mut fields = fields.into_iter().map(|field| {
-                        field.layout(infcx)
+                        field.layout(tcx, param_env)
                     }).collect::<Result<Vec<_>, _>>()?;
                     fields.insert(0, &discr);
                     let st = Struct::new(dl,
@@ -1470,11 +1496,11 @@ impl<'a, 'gcx, 'tcx> Layout {
 
             // Types with no meaningful known layout.
             ty::TyProjection(_) | ty::TyAnon(..) => {
-                let normalized = infcx.normalize_projections(ty);
+                let normalized = tcx.normalize_associated_type_in_env(&ty, param_env);
                 if ty == normalized {
                     return Err(LayoutError::Unknown(ty));
                 }
-                return normalized.layout(infcx);
+                return normalized.layout(tcx, param_env);
             }
             ty::TyParam(_) => {
                 return Err(LayoutError::Unknown(ty));
@@ -1686,21 +1712,22 @@ pub enum SizeSkeleton<'tcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
-    pub fn compute(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>)
-                   -> Result<SizeSkeleton<'gcx>, LayoutError<'gcx>> {
-        let tcx = infcx.tcx.global_tcx();
+impl<'a, 'tcx> SizeSkeleton<'tcx> {
+    pub fn compute(ty: Ty<'tcx>,
+                   tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                   param_env: ty::ParamEnv<'tcx>)
+                   -> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> {
         assert!(!ty.has_infer_types());
 
         // First try computing a static layout.
-        let err = match ty.layout(infcx) {
+        let err = match ty.layout(tcx, param_env) {
             Ok(layout) => {
                 return Ok(SizeSkeleton::Known(layout.size(tcx)));
             }
             Err(err) => err
         };
 
-        let ptr_skeleton = |pointee: Ty<'gcx>| {
+        let ptr_skeleton = |pointee: Ty<'tcx>| {
             let non_zero = !ty.is_unsafe_ptr();
             let tail = tcx.struct_tail(pointee);
             match tail.sty {
@@ -1737,7 +1764,7 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
                 // Get a zero-sized variant or a pointer newtype.
                 let zero_or_ptr_variant = |i: usize| {
                     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;
                     for field in fields {
@@ -1788,11 +1815,11 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
             }
 
             ty::TyProjection(_) | ty::TyAnon(..) => {
-                let normalized = infcx.normalize_projections(ty);
+                let normalized = tcx.normalize_associated_type_in_env(&ty, param_env);
                 if ty == normalized {
                     Err(err)
                 } 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 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> {
-    fn data_layout(&self) -> &TargetDataLayout {
-        &self.data_layout
-    }
+/// Combines a tcx with the parameter environment so that you can
+/// compute layout operations.
+#[derive(Copy, Clone)]
+pub struct LayoutCx<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
 }
 
-impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
-        self.global_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> HasDataLayout for &'a InferCtxt<'a, 'gcx, 'tcx> {
+impl<'a, 'tcx> HasDataLayout for LayoutCx<'a, 'tcx> {
     fn data_layout(&self) -> &TargetDataLayout {
         &self.tcx.data_layout
     }
 }
 
-impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
-        self.tcx.global_tcx()
-    }
-}
-
-pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> {
-    type TyLayout;
-
-    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout;
-    fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>;
-}
+impl<'a, 'tcx> LayoutTyper<'tcx> for LayoutCx<'a, 'tcx> {
+    type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
 
-impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
-    type TyLayout = Result<TyLayout<'gcx>, LayoutError<'gcx>>;
+    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
+        self.tcx
+    }
 
-    fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout {
+    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
         let ty = self.normalize_projections(ty);
 
         Ok(TyLayout {
             ty: ty,
-            layout: ty.layout(self)?,
+            layout: ty.layout(self.tcx, self.param_env)?,
             variant_index: None
         })
     }
 
-    fn normalize_projections(self, ty: Ty<'gcx>) -> Ty<'gcx> {
-        if !ty.has_projection_types() {
-            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)
+    fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.tcx.normalize_associated_type_in_env(&ty, self.param_env)
     }
 }
 
@@ -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 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)))
     }
 }
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index da85d40b2c3..b5adcc8ed75 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -20,6 +20,7 @@ use mir::transform::{MirSuite, MirPassIndex};
 use session::CompileResult;
 use traits::specialization_graph;
 use ty::{self, CrateInherentImpls, Ty, TyCtxt};
+use ty::layout::{Layout, LayoutError};
 use ty::item_path;
 use ty::steal::Steal;
 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> {
     fn describe(tcx: TyCtxt, def_id: DefId) -> String {
         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_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,
+    [] 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> {
@@ -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));
     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)
+}
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 31c099c661d..6d55f04e86a 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -12,7 +12,6 @@
 
 use hir::def_id::{DefId, LOCAL_CRATE};
 use hir::map::DefPathData;
-use infer::InferCtxt;
 use ich::{StableHashingContext, NodeIdHashingMode};
 use traits::{self, Reveal};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
@@ -791,35 +790,17 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
         tcx.needs_drop_raw(param_env.and(self))
     }
 
+    /// Computes the layout of a type. Note that this implicitly
+    /// executes in "reveal all" mode.
     #[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>> {
-        let tcx = infcx.tcx.global_tcx();
-        let can_cache = !self.has_param_types() && !self.has_self_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)
+        let ty = tcx.erase_regions(&self);
+        tcx.layout_raw(param_env.reveal_all().and(ty))
     }
 
-
     /// Check whether a type is representable. This means it cannot contain unboxed
     /// structural recursion. This check is needed for structs and enums.
     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) {
     *providers = ty::maps::Providers {
@@ -1081,6 +1080,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
         is_sized_raw,
         is_freeze_raw,
         needs_drop_raw,
+        layout_raw,
         ..*providers
     };
 }
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 1b86085d99d..3019165bfbf 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -14,7 +14,6 @@ use rustc::hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, AdtKind, Ty, TyCtxt};
 use rustc::ty::layout::{Layout, Primitive};
-use rustc::traits::Reveal;
 use middle::const_val::ConstVal;
 use rustc_const_eval::ConstContext;
 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 gens.ty_params.is_empty() {
                 // sizes only make sense for non-generic types
-                let t = cx.tcx.type_of(cx.tcx.hir.local_def_id(it.id));
-                let layout = cx.tcx.infer_ctxt(Reveal::All).enter(|infcx| {
-                    let ty = cx.tcx.erase_regions(&t);
-                    ty.layout(&infcx).unwrap_or_else(|e| {
-                        bug!("failed to get layout for `{}`: {}", t, e)
-                    })
+                let item_def_id = cx.tcx.hir.local_def_id(it.id);
+                let t = cx.tcx.type_of(item_def_id);
+                let param_env = cx.tcx.param_env(item_def_id).reveal_all();
+                let ty = cx.tcx.erase_regions(&t);
+                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 {
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 8842d30b65c..0ac35a5fdd4 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -547,10 +547,8 @@ 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.infer_ctxt(param_env.reveal_all()).enter(|infcx| {
-        ty.layout(&infcx).ok().map(|layout| {
-            layout.size(&tcx.data_layout).bytes()
-        })
+    ty.layout(tcx, param_env).ok().map(|layout| {
+        layout.size(&tcx.data_layout).bytes()
     })
 }
 
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 56f51cae147..1a13c8e6f3d 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -25,10 +25,10 @@ use type_::Type;
 use rustc_data_structures::base_n;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::layout::{LayoutTyper, TyLayout};
-use rustc::session::config::{self, NoDebugInfo};
-use rustc::session::Session;
-use rustc::util::nodemap::{NodeSet, DefIdMap, FxHashMap};
+use rustc::ty::layout::{LayoutCx, LayoutError, LayoutTyper, TyLayout};
+use session::config::{self, NoDebugInfo};
+use session::Session;
+use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
 
 use std::ffi::{CStr, CString};
 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> {
     fn data_layout(&self) -> &ty::layout::TargetDataLayout {
         &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> {
     type TyLayout = TyLayout<'tcx>;
 
-    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
-        if let Some(&layout) = self.tcx().layout_cache.borrow().get(&ty) {
-            return TyLayout { ty: ty, layout: layout, variant_index: None };
-        }
+    fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
+        self.tcx
+    }
 
-        self.tcx().infer_ctxt(traits::Reveal::All).enter(|infcx| {
-            infcx.layout_of(ty).unwrap_or_else(|e| {
-                match e {
-                    ty::layout::LayoutError::SizeOverflow(_) =>
-                        self.sess().fatal(&e.to_string()),
-                    _ => bug!("failed to get layout for `{}`: {}", ty, e)
-                }
+    fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
+        let param_env = ty::ParamEnv::empty(traits::Reveal::All);
+        LayoutCx::new(self.tcx, param_env)
+            .layout_of(ty)
+            .unwrap_or_else(|e| match 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> {
@@ -754,6 +740,10 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
 impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, '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 {
         self.shared.layout_of(ty)
     }
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index f473d957a90..367f0398fa8 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -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() => {
             let typ = t.boxed_ty();
             if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) {
-                scx.tcx().infer_ctxt(traits::Reveal::All).enter(|infcx| {
-                    let layout = t.layout(&infcx).unwrap();
-                    if layout.size(scx).bytes() == 0 {
-                        // `Box<ZeroSizeType>` does not allocate.
-                        false
-                    } else {
-                        true
-                    }
-                })
+                let layout = t.layout(scx.tcx(), ty::ParamEnv::empty(traits::Reveal::All)).unwrap();
+                if layout.size(scx).bytes() == 0 {
+                    // `Box<ZeroSizeType>` does not allocate.
+                    false
+                } else {
+                    true
+                }
             } else {
                 true
             }