diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index f21d98a0fc7f9..4d66bba9f07ee 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -327,10 +327,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                 self.opt_expr(base, field_cfg)
             }
 
-            hir::ExprRepeat(ref elem, ref count) => {
-                self.straightline(expr, pred, [elem, count].iter().map(|&e| &**e))
-            }
-
             hir::ExprAssign(ref l, ref r) |
             hir::ExprAssignOp(_, ref l, ref r) => {
                 self.straightline(expr, pred, [r, l].iter().map(|&e| &**e))
@@ -347,7 +343,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             hir::ExprType(ref e, _) |
             hir::ExprUnary(_, ref e) |
             hir::ExprField(ref e, _) |
-            hir::ExprTupField(ref e, _) => {
+            hir::ExprTupField(ref e, _) |
+            hir::ExprRepeat(ref e, _) => {
                 self.straightline(expr, pred, Some(&**e).into_iter())
             }
 
diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs
index 2637d34c5c56e..26e1dc7e0490c 100644
--- a/src/librustc/dep_graph/graph.rs
+++ b/src/librustc/dep_graph/graph.rs
@@ -51,6 +51,12 @@ impl DepGraph {
         }
     }
 
+    /// True if we are actually building the full dep-graph.
+    #[inline]
+    pub fn is_fully_enabled(&self) -> bool {
+        self.data.thread.is_fully_enabled()
+    }
+
     pub fn query(&self) -> DepGraphQuery<DefId> {
         self.data.thread.query()
     }
diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs
index f6a22e47cf212..1990574ca9a83 100644
--- a/src/librustc/dep_graph/visit.rs
+++ b/src/librustc/dep_graph/visit.rs
@@ -45,6 +45,16 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>
             debug!("Ended task {:?}", task_id);
         }
 
+        fn visit_trait_item(&mut self, i: &'tcx hir::TraitItem) {
+            let trait_item_def_id = self.tcx.map.local_def_id(i.id);
+            let task_id = (self.dep_node_fn)(trait_item_def_id);
+            let _task = self.tcx.dep_graph.in_task(task_id.clone());
+            debug!("Started task {:?}", task_id);
+            self.tcx.dep_graph.read(DepNode::Hir(trait_item_def_id));
+            self.visitor.visit_trait_item(i);
+            debug!("Ended task {:?}", task_id);
+        }
+
         fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) {
             let impl_item_def_id = self.tcx.map.local_def_id(i.id);
             let task_id = (self.dep_node_fn)(impl_item_def_id);
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 474d7d508c45b..4b171193b4af1 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -177,6 +177,17 @@ pub trait Visitor<'v> : Sized {
         }
     }
 
+    /// Like `visit_nested_item()`, but for trait items. See
+    /// `visit_nested_item()` for advice on when to override this
+    /// method.
+    #[allow(unused_variables)]
+    fn visit_nested_trait_item(&mut self, id: TraitItemId) {
+        let opt_item = self.nested_visit_map().inter().map(|map| map.trait_item(id));
+        if let Some(item) = opt_item {
+            self.visit_trait_item(item);
+        }
+    }
+
     /// Like `visit_nested_item()`, but for impl items. See
     /// `visit_nested_item()` for advice on when to override this
     /// method.
@@ -192,10 +203,10 @@ pub trait Visitor<'v> : Sized {
     /// visit_nested_item, does nothing by default unless you override
     /// `nested_visit_map` to return `Some(_)`, in which case it will walk the
     /// body.
-    fn visit_body(&mut self, id: ExprId) {
-        let opt_expr = self.nested_visit_map().intra().map(|map| map.expr(id));
-        if let Some(expr) = opt_expr {
-            self.visit_expr(expr);
+    fn visit_nested_body(&mut self, id: BodyId) {
+        let opt_body = self.nested_visit_map().intra().map(|map| map.body(id));
+        if let Some(body) = opt_body {
+            self.visit_body(body);
         }
     }
 
@@ -205,6 +216,10 @@ pub trait Visitor<'v> : Sized {
         walk_item(self, i)
     }
 
+    fn visit_body(&mut self, b: &'v Body) {
+        walk_body(self, b);
+    }
+
     /// When invoking `visit_all_item_likes()`, you need to supply an
     /// item-like visitor.  This method converts a "intra-visit"
     /// visitor into an item-like visitor that walks the entire tree.
@@ -253,8 +268,6 @@ pub trait Visitor<'v> : Sized {
     fn visit_expr(&mut self, ex: &'v Expr) {
         walk_expr(self, ex)
     }
-    fn visit_expr_post(&mut self, _ex: &'v Expr) {
-    }
     fn visit_ty(&mut self, t: &'v Ty) {
         walk_ty(self, t)
     }
@@ -267,12 +280,15 @@ pub trait Visitor<'v> : Sized {
     fn visit_fn_decl(&mut self, fd: &'v FnDecl) {
         walk_fn_decl(self, fd)
     }
-    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: ExprId, s: Span, id: NodeId) {
+    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: BodyId, s: Span, id: NodeId) {
         walk_fn(self, fk, fd, b, s, id)
     }
     fn visit_trait_item(&mut self, ti: &'v TraitItem) {
         walk_trait_item(self, ti)
     }
+    fn visit_trait_item_ref(&mut self, ii: &'v TraitItemRef) {
+        walk_trait_item_ref(self, ii)
+    }
     fn visit_impl_item(&mut self, ii: &'v ImplItem) {
         walk_impl_item(self, ii)
     }
@@ -378,6 +394,14 @@ pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod, mod_node_i
     }
 }
 
+pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) {
+    for argument in &body.arguments {
+        visitor.visit_id(argument.id);
+        visitor.visit_pat(&argument.pat);
+    }
+    visitor.visit_expr(&body.value);
+}
+
 pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
     visitor.visit_id(local.id);
     visitor.visit_pat(&local.pat);
@@ -423,11 +447,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
             visitor.visit_id(item.id);
             visitor.visit_path(path, item.id);
         }
-        ItemStatic(ref typ, _, ref expr) |
-        ItemConst(ref typ, ref expr) => {
+        ItemStatic(ref typ, _, body) |
+        ItemConst(ref typ, body) => {
             visitor.visit_id(item.id);
             visitor.visit_ty(typ);
-            visitor.visit_expr(expr);
+            visitor.visit_nested_body(body);
         }
         ItemFn(ref declaration, unsafety, constness, abi, ref generics, body_id) => {
             visitor.visit_fn(FnKind::ItemFn(item.name,
@@ -469,9 +493,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
             visitor.visit_generics(type_parameters);
             walk_list!(visitor, visit_trait_ref, opt_trait_reference);
             visitor.visit_ty(typ);
-            for impl_item_ref in impl_item_refs {
-                visitor.visit_impl_item_ref(impl_item_ref);
-            }
+            walk_list!(visitor, visit_impl_item_ref, impl_item_refs);
         }
         ItemStruct(ref struct_definition, ref generics) |
         ItemUnion(ref struct_definition, ref generics) => {
@@ -479,11 +501,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
             visitor.visit_id(item.id);
             visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span);
         }
-        ItemTrait(_, ref generics, ref bounds, ref methods) => {
+        ItemTrait(_, ref generics, ref bounds, ref trait_item_refs) => {
             visitor.visit_id(item.id);
             visitor.visit_generics(generics);
             walk_list!(visitor, visit_ty_param_bound, bounds);
-            walk_list!(visitor, visit_trait_item, methods);
+            walk_list!(visitor, visit_trait_item_ref, trait_item_refs);
         }
     }
     walk_list!(visitor, visit_attribute, &item.attrs);
@@ -511,7 +533,7 @@ pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V,
                                generics,
                                parent_item_id,
                                variant.span);
-    walk_list!(visitor, visit_expr, &variant.node.disr_expr);
+    walk_list!(visitor, visit_nested_body, variant.node.disr_expr);
     walk_list!(visitor, visit_attribute, &variant.node.attrs);
 }
 
@@ -544,9 +566,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
             visitor.visit_ty(ty);
             walk_list!(visitor, visit_ty_param_bound, bounds);
         }
-        TyArray(ref ty, ref expression) => {
+        TyArray(ref ty, length) => {
             visitor.visit_ty(ty);
-            visitor.visit_expr(expression)
+            visitor.visit_nested_body(length)
         }
         TyPolyTraitRef(ref bounds) => {
             walk_list!(visitor, visit_ty_param_bound, bounds);
@@ -554,8 +576,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
         TyImplTrait(ref bounds) => {
             walk_list!(visitor, visit_ty_param_bound, bounds);
         }
-        TyTypeof(ref expression) => {
-            visitor.visit_expr(expression)
+        TyTypeof(expression) => {
+            visitor.visit_nested_body(expression)
         }
         TyInfer => {}
     }
@@ -662,9 +684,12 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v
     visitor.visit_name(foreign_item.span, foreign_item.name);
 
     match foreign_item.node {
-        ForeignItemFn(ref function_declaration, ref generics) => {
+        ForeignItemFn(ref function_declaration, ref names, ref generics) => {
+            visitor.visit_generics(generics);
             visitor.visit_fn_decl(function_declaration);
-            visitor.visit_generics(generics)
+            for name in names {
+                visitor.visit_name(name.span, name.node);
+            }
         }
         ForeignItemStatic(ref typ, _) => visitor.visit_ty(typ),
     }
@@ -732,18 +757,8 @@ pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionR
 }
 
 pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
-    for argument in &function_declaration.inputs {
-        visitor.visit_id(argument.id);
-        visitor.visit_pat(&argument.pat);
-        visitor.visit_ty(&argument.ty)
-    }
-    walk_fn_ret_ty(visitor, &function_declaration.output)
-}
-
-pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
-    for argument in &function_declaration.inputs {
-        visitor.visit_id(argument.id);
-        visitor.visit_ty(&argument.ty)
+    for ty in &function_declaration.inputs {
+        visitor.visit_ty(ty)
     }
     walk_fn_ret_ty(visitor, &function_declaration.output)
 }
@@ -763,42 +778,33 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'
 pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V,
                                    function_kind: FnKind<'v>,
                                    function_declaration: &'v FnDecl,
-                                   body_id: ExprId,
+                                   body_id: BodyId,
                                    _span: Span,
                                    id: NodeId) {
     visitor.visit_id(id);
     visitor.visit_fn_decl(function_declaration);
     walk_fn_kind(visitor, function_kind);
-    visitor.visit_body(body_id)
-}
-
-pub fn walk_fn_with_body<'v, V: Visitor<'v>>(visitor: &mut V,
-                                             function_kind: FnKind<'v>,
-                                             function_declaration: &'v FnDecl,
-                                             body: &'v Expr,
-                                             _span: Span,
-                                             id: NodeId) {
-    visitor.visit_id(id);
-    visitor.visit_fn_decl(function_declaration);
-    walk_fn_kind(visitor, function_kind);
-    visitor.visit_expr(body)
+    visitor.visit_nested_body(body_id)
 }
 
 pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) {
     visitor.visit_name(trait_item.span, trait_item.name);
     walk_list!(visitor, visit_attribute, &trait_item.attrs);
     match trait_item.node {
-        ConstTraitItem(ref ty, ref default) => {
+        TraitItemKind::Const(ref ty, default) => {
             visitor.visit_id(trait_item.id);
             visitor.visit_ty(ty);
-            walk_list!(visitor, visit_expr, default);
+            walk_list!(visitor, visit_nested_body, default);
         }
-        MethodTraitItem(ref sig, None) => {
+        TraitItemKind::Method(ref sig, TraitMethod::Required(ref names)) => {
             visitor.visit_id(trait_item.id);
             visitor.visit_generics(&sig.generics);
             visitor.visit_fn_decl(&sig.decl);
+            for name in names {
+                visitor.visit_name(name.span, name.node);
+            }
         }
-        MethodTraitItem(ref sig, Some(body_id)) => {
+        TraitItemKind::Method(ref sig, TraitMethod::Provided(body_id)) => {
             visitor.visit_fn(FnKind::Method(trait_item.name,
                                             sig,
                                             None,
@@ -808,7 +814,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
                              trait_item.span,
                              trait_item.id);
         }
-        TypeTraitItem(ref bounds, ref default) => {
+        TraitItemKind::Type(ref bounds, ref default) => {
             visitor.visit_id(trait_item.id);
             walk_list!(visitor, visit_ty_param_bound, bounds);
             walk_list!(visitor, visit_ty, default);
@@ -816,6 +822,15 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
     }
 }
 
+pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref: &'v TraitItemRef) {
+    // NB: Deliberately force a compilation error if/when new fields are added.
+    let TraitItemRef { id, name, ref kind, span, ref defaultness } = *trait_item_ref;
+    visitor.visit_nested_trait_item(id);
+    visitor.visit_name(span, name);
+    visitor.visit_associated_item_kind(kind);
+    visitor.visit_defaultness(defaultness);
+}
+
 pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem) {
     // NB: Deliberately force a compilation error if/when new fields are added.
     let ImplItem { id: _, name, ref vis, ref defaultness, ref attrs, ref node, span } = *impl_item;
@@ -825,10 +840,10 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
     visitor.visit_defaultness(defaultness);
     walk_list!(visitor, visit_attribute, attrs);
     match *node {
-        ImplItemKind::Const(ref ty, ref expr) => {
+        ImplItemKind::Const(ref ty, body) => {
             visitor.visit_id(impl_item.id);
             visitor.visit_ty(ty);
-            visitor.visit_expr(expr);
+            visitor.visit_nested_body(body);
         }
         ImplItemKind::Method(ref sig, body_id) => {
             visitor.visit_fn(FnKind::Method(impl_item.name,
@@ -907,9 +922,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
         ExprArray(ref subexpressions) => {
             walk_list!(visitor, visit_expr, subexpressions);
         }
-        ExprRepeat(ref element, ref count) => {
+        ExprRepeat(ref element, count) => {
             visitor.visit_expr(element);
-            visitor.visit_expr(count)
+            visitor.visit_nested_body(count)
         }
         ExprStruct(ref qpath, ref fields, ref optional_base) => {
             visitor.visit_qpath(qpath, expression.id, expression.span);
@@ -1016,8 +1031,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             }
         }
     }
-
-    visitor.visit_expr_post(expression)
 }
 
 pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) {
@@ -1100,16 +1113,3 @@ impl<'a, 'ast> Visitor<'ast> for IdRangeComputingVisitor<'a, 'ast> {
         self.result.add(id);
     }
 }
-
-/// Computes the id range for a single fn body, ignoring nested items.
-pub fn compute_id_range_for_fn_body<'v>(fk: FnKind<'v>,
-                                        decl: &'v FnDecl,
-                                        body: &'v Expr,
-                                        sp: Span,
-                                        id: NodeId,
-                                        map: &map::Map<'v>)
-                                        -> IdRange {
-    let mut visitor = IdRangeComputingVisitor::new(map);
-    walk_fn_with_body(&mut visitor, fk, decl, body, sp, id);
-    visitor.result()
-}
diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs
index 71ef7131440b8..f359ca2016359 100644
--- a/src/librustc/hir/itemlikevisit.rs
+++ b/src/librustc/hir/itemlikevisit.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use super::{Item, ImplItem};
+use super::{Item, ImplItem, TraitItem};
 use super::intravisit::Visitor;
 
 /// The "item-like visitor" visitor defines only the top-level methods
@@ -58,6 +58,7 @@ use super::intravisit::Visitor;
 /// needed.
 pub trait ItemLikeVisitor<'hir> {
     fn visit_item(&mut self, item: &'hir Item);
+    fn visit_trait_item(&mut self, trait_item: &'hir TraitItem);
     fn visit_impl_item(&mut self, impl_item: &'hir ImplItem);
 }
 
@@ -80,6 +81,10 @@ impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V>
         self.visitor.visit_item(item);
     }
 
+    fn visit_trait_item(&mut self, trait_item: &'hir TraitItem) {
+        self.visitor.visit_trait_item(trait_item);
+    }
+
     fn visit_impl_item(&mut self, impl_item: &'hir ImplItem) {
         self.visitor.visit_impl_item(impl_item);
     }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 1cf5e35a0957f..9a2658f48f3d9 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -46,12 +46,10 @@ use hir::map::definitions::DefPathData;
 use hir::def_id::{DefIndex, DefId};
 use hir::def::{Def, PathResolution};
 use session::Session;
-use util::nodemap::NodeMap;
-use rustc_data_structures::fnv::FnvHashMap;
+use util::nodemap::{NodeMap, FxHashMap};
 
 use std::collections::BTreeMap;
 use std::iter;
-use std::mem;
 
 use syntax::ast::*;
 use syntax::errors;
@@ -71,13 +69,14 @@ pub struct LoweringContext<'a> {
     // the form of a DefIndex) so that if we create a new node which introduces
     // a definition, then we can properly create the def id.
     parent_def: Option<DefIndex>,
-    exprs: FnvHashMap<hir::ExprId, hir::Expr>,
     resolver: &'a mut Resolver,
 
     /// The items being lowered are collected here.
     items: BTreeMap<NodeId, hir::Item>,
 
+    trait_items: BTreeMap<hir::TraitItemId, hir::TraitItem>,
     impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
+    bodies: FxHashMap<hir::BodyId, hir::Body>,
 }
 
 pub trait Resolver {
@@ -105,10 +104,11 @@ pub fn lower_crate(sess: &Session,
         crate_root: std_inject::injected_crate_name(krate),
         sess: sess,
         parent_def: None,
-        exprs: FnvHashMap(),
         resolver: resolver,
         items: BTreeMap::new(),
+        trait_items: BTreeMap::new(),
         impl_items: BTreeMap::new(),
+        bodies: FxHashMap(),
     }.lower_crate(krate)
 }
 
@@ -133,8 +133,9 @@ impl<'a> LoweringContext<'a> {
             span: c.span,
             exported_macros: exported_macros,
             items: self.items,
+            trait_items: self.trait_items,
             impl_items: self.impl_items,
-            exprs: mem::replace(&mut self.exprs, FnvHashMap()),
+            bodies: self.bodies,
         }
     }
 
@@ -150,8 +151,15 @@ impl<'a> LoweringContext<'a> {
                 visit::walk_item(self, item);
             }
 
+            fn visit_trait_item(&mut self, item: &'lcx TraitItem) {
+                let id = hir::TraitItemId { node_id: item.id };
+                let hir_item = self.lctx.lower_trait_item(item);
+                self.lctx.trait_items.insert(id, hir_item);
+                visit::walk_trait_item(self, item);
+            }
+
             fn visit_impl_item(&mut self, item: &'lcx ImplItem) {
-                let id = self.lctx.lower_impl_item_ref(item).id;
+                let id = hir::ImplItemId { node_id: item.id };
                 let hir_item = self.lctx.lower_impl_item(item);
                 self.lctx.impl_items.insert(id, hir_item);
                 visit::walk_impl_item(self, item);
@@ -162,9 +170,16 @@ impl<'a> LoweringContext<'a> {
         visit::walk_crate(&mut item_lowerer, c);
     }
 
-    fn record_expr(&mut self, expr: hir::Expr) -> hir::ExprId {
-        let id = hir::ExprId(expr.id);
-        self.exprs.insert(id, expr);
+    fn record_body(&mut self, value: hir::Expr, decl: Option<&FnDecl>)
+                   -> hir::BodyId {
+        let body = hir::Body {
+            arguments: decl.map_or(hir_vec![], |decl| {
+                decl.inputs.iter().map(|x| self.lower_arg(x)).collect()
+            }),
+            value: value
+        };
+        let id = body.id();
+        self.bodies.insert(id, body);
         id
     }
 
@@ -259,7 +274,7 @@ impl<'a> LoweringContext<'a> {
         P(hir::Ty {
             id: t.id,
             node: match t.node {
-                TyKind::Infer | TyKind::ImplicitSelf => hir::TyInfer,
+                TyKind::Infer => hir::TyInfer,
                 TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)),
                 TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)),
                 TyKind::Rptr(ref region, ref mt) => {
@@ -283,14 +298,27 @@ impl<'a> LoweringContext<'a> {
                 TyKind::Path(ref qself, ref path) => {
                     hir::TyPath(self.lower_qpath(t.id, qself, path, ParamMode::Explicit))
                 }
+                TyKind::ImplicitSelf => {
+                    hir::TyPath(hir::QPath::Resolved(None, P(hir::Path {
+                        def: self.expect_full_def(t.id),
+                        segments: hir_vec![hir::PathSegment {
+                            name: keywords::SelfType.name(),
+                            parameters: hir::PathParameters::none()
+                        }],
+                        span: t.span,
+                    })))
+                }
                 TyKind::ObjectSum(ref ty, ref bounds) => {
                     hir::TyObjectSum(self.lower_ty(ty), self.lower_bounds(bounds))
                 }
-                TyKind::Array(ref ty, ref e) => {
-                    hir::TyArray(self.lower_ty(ty), P(self.lower_expr(e)))
+                TyKind::Array(ref ty, ref length) => {
+                    let length = self.lower_expr(length);
+                    hir::TyArray(self.lower_ty(ty),
+                                 self.record_body(length, None))
                 }
                 TyKind::Typeof(ref expr) => {
-                    hir::TyTypeof(P(self.lower_expr(expr)))
+                    let expr = self.lower_expr(expr);
+                    hir::TyTypeof(self.record_body(expr, None))
                 }
                 TyKind::PolyTraitRef(ref bounds) => {
                     hir::TyPolyTraitRef(self.lower_bounds(bounds))
@@ -317,7 +345,10 @@ impl<'a> LoweringContext<'a> {
                 name: v.node.name.name,
                 attrs: self.lower_attrs(&v.node.attrs),
                 data: self.lower_variant_data(&v.node.data),
-                disr_expr: v.node.disr_expr.as_ref().map(|e| P(self.lower_expr(e))),
+                disr_expr: v.node.disr_expr.as_ref().map(|e| {
+                    let e = self.lower_expr(e);
+                    self.record_body(e, None)
+                }),
             },
             span: v.span,
         }
@@ -505,13 +536,24 @@ impl<'a> LoweringContext<'a> {
         hir::Arg {
             id: arg.id,
             pat: self.lower_pat(&arg.pat),
-            ty: self.lower_ty(&arg.ty),
         }
     }
 
+    fn lower_fn_args_to_names(&mut self, decl: &FnDecl)
+                              -> hir::HirVec<Spanned<Name>> {
+        decl.inputs.iter().map(|arg| {
+            match arg.pat.node {
+                PatKind::Ident(_, ident, None) => {
+                    respan(ident.span, ident.node.name)
+                }
+                _ => respan(arg.pat.span, keywords::Invalid.name()),
+            }
+        }).collect()
+    }
+
     fn lower_fn_decl(&mut self, decl: &FnDecl) -> P<hir::FnDecl> {
         P(hir::FnDecl {
-            inputs: decl.inputs.iter().map(|x| self.lower_arg(x)).collect(),
+            inputs: decl.inputs.iter().map(|arg| self.lower_ty(&arg.ty)).collect(),
             output: match decl.output {
                 FunctionRetTy::Ty(ref ty) => hir::Return(self.lower_ty(ty)),
                 FunctionRetTy::Default(span) => hir::DefaultReturn(span),
@@ -839,17 +881,20 @@ impl<'a> LoweringContext<'a> {
                 hir::ItemUse(path, kind)
             }
             ItemKind::Static(ref t, m, ref e) => {
+                let value = self.lower_expr(e);
                 hir::ItemStatic(self.lower_ty(t),
                                 self.lower_mutability(m),
-                                P(self.lower_expr(e)))
+                                self.record_body(value, None))
             }
             ItemKind::Const(ref t, ref e) => {
-                hir::ItemConst(self.lower_ty(t), P(self.lower_expr(e)))
+                let value = self.lower_expr(e);
+                hir::ItemConst(self.lower_ty(t),
+                               self.record_body(value, None))
             }
             ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
                 let body = self.lower_block(body);
                 let body = self.expr_block(body, ThinVec::new());
-                let body_id = self.record_expr(body);
+                let body_id = self.record_body(body, Some(decl));
                 hir::ItemFn(self.lower_fn_decl(decl),
                             self.lower_unsafety(unsafety),
                             self.lower_constness(constness),
@@ -897,7 +942,7 @@ impl<'a> LoweringContext<'a> {
             }
             ItemKind::Trait(unsafety, ref generics, ref bounds, ref items) => {
                 let bounds = self.lower_bounds(bounds);
-                let items = items.iter().map(|item| self.lower_trait_item(item)).collect();
+                let items = items.iter().map(|item| self.lower_trait_item_ref(item)).collect();
                 hir::ItemTrait(self.lower_unsafety(unsafety),
                                self.lower_generics(generics),
                                bounds,
@@ -915,20 +960,27 @@ impl<'a> LoweringContext<'a> {
                 attrs: this.lower_attrs(&i.attrs),
                 node: match i.node {
                     TraitItemKind::Const(ref ty, ref default) => {
-                        hir::ConstTraitItem(this.lower_ty(ty),
-                                            default.as_ref().map(|x| P(this.lower_expr(x))))
-                    }
-                    TraitItemKind::Method(ref sig, ref body) => {
-                        hir::MethodTraitItem(this.lower_method_sig(sig),
-                                             body.as_ref().map(|x| {
-                            let body = this.lower_block(x);
-                            let expr = this.expr_block(body, ThinVec::new());
-                            this.record_expr(expr)
+                        hir::TraitItemKind::Const(this.lower_ty(ty),
+                                                  default.as_ref().map(|x| {
+                            let value = this.lower_expr(x);
+                            this.record_body(value, None)
                         }))
                     }
+                    TraitItemKind::Method(ref sig, None) => {
+                        let names = this.lower_fn_args_to_names(&sig.decl);
+                        hir::TraitItemKind::Method(this.lower_method_sig(sig),
+                                                   hir::TraitMethod::Required(names))
+                    }
+                    TraitItemKind::Method(ref sig, Some(ref body)) => {
+                        let body = this.lower_block(body);
+                        let expr = this.expr_block(body, ThinVec::new());
+                        let body_id = this.record_body(expr, Some(&sig.decl));
+                        hir::TraitItemKind::Method(this.lower_method_sig(sig),
+                                                   hir::TraitMethod::Provided(body_id))
+                    }
                     TraitItemKind::Type(ref bounds, ref default) => {
-                        hir::TypeTraitItem(this.lower_bounds(bounds),
-                                           default.as_ref().map(|x| this.lower_ty(x)))
+                        hir::TraitItemKind::Type(this.lower_bounds(bounds),
+                                                 default.as_ref().map(|x| this.lower_ty(x)))
                     }
                     TraitItemKind::Macro(..) => panic!("Shouldn't exist any more"),
                 },
@@ -937,6 +989,30 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
+    fn lower_trait_item_ref(&mut self, i: &TraitItem) -> hir::TraitItemRef {
+        let (kind, has_default) = match i.node {
+            TraitItemKind::Const(_, ref default) => {
+                (hir::AssociatedItemKind::Const, default.is_some())
+            }
+            TraitItemKind::Type(_, ref default) => {
+                (hir::AssociatedItemKind::Type, default.is_some())
+            }
+            TraitItemKind::Method(ref sig, ref default) => {
+                (hir::AssociatedItemKind::Method {
+                    has_self: sig.decl.has_self(),
+                 }, default.is_some())
+            }
+            TraitItemKind::Macro(..) => unimplemented!(),
+        };
+        hir::TraitItemRef {
+            id: hir::TraitItemId { node_id: i.id },
+            name: i.ident.name,
+            span: i.span,
+            defaultness: self.lower_defaultness(Defaultness::Default, has_default),
+            kind: kind,
+        }
+    }
+
     fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem {
         self.with_parent_def(i.id, |this| {
             hir::ImplItem {
@@ -947,13 +1023,15 @@ impl<'a> LoweringContext<'a> {
                 defaultness: this.lower_defaultness(i.defaultness, true /* [1] */),
                 node: match i.node {
                     ImplItemKind::Const(ref ty, ref expr) => {
-                        hir::ImplItemKind::Const(this.lower_ty(ty), P(this.lower_expr(expr)))
+                        let value = this.lower_expr(expr);
+                        let body_id = this.record_body(value, None);
+                        hir::ImplItemKind::Const(this.lower_ty(ty), body_id)
                     }
                     ImplItemKind::Method(ref sig, ref body) => {
                         let body = this.lower_block(body);
                         let expr = this.expr_block(body, ThinVec::new());
-                        let expr_id = this.record_expr(expr);
-                        hir::ImplItemKind::Method(this.lower_method_sig(sig), expr_id)
+                        let body_id = this.record_body(expr, Some(&sig.decl));
+                        hir::ImplItemKind::Method(this.lower_method_sig(sig), body_id)
                     }
                     ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)),
                     ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
@@ -976,7 +1054,7 @@ impl<'a> LoweringContext<'a> {
                 ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
                 ImplItemKind::Type(..) => hir::AssociatedItemKind::Type,
                 ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method {
-                    has_self: sig.decl.get_self().is_some(),
+                    has_self: sig.decl.has_self(),
                 },
                 ImplItemKind::Macro(..) => unimplemented!(),
             },
@@ -1038,7 +1116,9 @@ impl<'a> LoweringContext<'a> {
                 attrs: this.lower_attrs(&i.attrs),
                 node: match i.node {
                     ForeignItemKind::Fn(ref fdec, ref generics) => {
-                        hir::ForeignItemFn(this.lower_fn_decl(fdec), this.lower_generics(generics))
+                        hir::ForeignItemFn(this.lower_fn_decl(fdec),
+                                           this.lower_fn_args_to_names(fdec),
+                                           this.lower_generics(generics))
                     }
                     ForeignItemKind::Static(ref t, m) => {
                         hir::ForeignItemStatic(this.lower_ty(t), m)
@@ -1051,24 +1131,13 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn lower_method_sig(&mut self, sig: &MethodSig) -> hir::MethodSig {
-        let hir_sig = hir::MethodSig {
+        hir::MethodSig {
             generics: self.lower_generics(&sig.generics),
             abi: sig.abi,
             unsafety: self.lower_unsafety(sig.unsafety),
             constness: self.lower_constness(sig.constness),
             decl: self.lower_fn_decl(&sig.decl),
-        };
-        // Check for `self: _` and `self: &_`
-        if let Some(SelfKind::Explicit(..)) = sig.decl.get_self().map(|eself| eself.node) {
-            match hir_sig.decl.get_self().map(|eself| eself.node) {
-                Some(hir::SelfKind::Value(..)) | Some(hir::SelfKind::Region(..)) => {
-                    self.diagnostic().span_err(sig.decl.inputs[0].ty.span,
-                        "the type placeholder `_` is not allowed within types on item signatures");
-                }
-                _ => {}
-            }
         }
-        hir_sig
     }
 
     fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety {
@@ -1318,8 +1387,8 @@ impl<'a> LoweringContext<'a> {
                 }
                 ExprKind::Repeat(ref expr, ref count) => {
                     let expr = P(self.lower_expr(expr));
-                    let count = P(self.lower_expr(count));
-                    hir::ExprRepeat(expr, count)
+                    let count = self.lower_expr(count);
+                    hir::ExprRepeat(expr, self.record_body(count, None))
                 }
                 ExprKind::Tup(ref elts) => {
                     hir::ExprTup(elts.iter().map(|x| self.lower_expr(x)).collect())
@@ -1402,7 +1471,7 @@ impl<'a> LoweringContext<'a> {
                         let expr = this.lower_expr(body);
                         hir::ExprClosure(this.lower_capture_clause(capture_clause),
                                          this.lower_fn_decl(decl),
-                                         this.record_expr(expr),
+                                         this.record_body(expr, Some(decl)),
                                          fn_decl_span)
                     })
                 }
@@ -1686,13 +1755,7 @@ impl<'a> LoweringContext<'a> {
                     // `::std::option::Option::Some(<pat>) => <body>`
                     let pat_arm = {
                         let body_block = self.lower_block(body);
-                        let body_span = body_block.span;
-                        let body_expr = P(hir::Expr {
-                            id: self.next_id(),
-                            node: hir::ExprBlock(body_block),
-                            span: body_span,
-                            attrs: ThinVec::new(),
-                        });
+                        let body_expr = P(self.expr_block(body_block, ThinVec::new()));
                         let pat = self.lower_pat(pat);
                         let some_pat = self.pat_some(e.span, pat);
 
diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs
index 068e7ed8624ed..6e08b52f9a249 100644
--- a/src/librustc/hir/map/blocks.rs
+++ b/src/librustc/hir/map/blocks.rs
@@ -48,7 +48,7 @@ pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; }
 /// Components shared by fn-like things (fn items, methods, closures).
 pub struct FnParts<'a> {
     pub decl: &'a FnDecl,
-    pub body: ast::ExprId,
+    pub body: ast::BodyId,
     pub kind: FnKind<'a>,
     pub span: Span,
     pub id:   NodeId,
@@ -62,7 +62,10 @@ impl MaybeFnLike for ast::Item {
 
 impl MaybeFnLike for ast::TraitItem {
     fn is_fn_like(&self) -> bool {
-        match self.node { ast::MethodTraitItem(_, Some(_)) => true, _ => false, }
+        match self.node {
+            ast::TraitItemKind::Method(_, ast::TraitMethod::Provided(_)) => true,
+            _ => false,
+        }
     }
 }
 
@@ -115,7 +118,7 @@ struct ItemFnParts<'a> {
     abi:      abi::Abi,
     vis:      &'a ast::Visibility,
     generics: &'a ast::Generics,
-    body:     ast::ExprId,
+    body:     ast::BodyId,
     id:       NodeId,
     span:     Span,
     attrs:    &'a [Attribute],
@@ -125,14 +128,14 @@ struct ItemFnParts<'a> {
 /// for use when implementing FnLikeNode operations.
 struct ClosureParts<'a> {
     decl: &'a FnDecl,
-    body: ast::ExprId,
+    body: ast::BodyId,
     id: NodeId,
     span: Span,
     attrs: &'a [Attribute],
 }
 
 impl<'a> ClosureParts<'a> {
-    fn new(d: &'a FnDecl, b: ast::ExprId, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
+    fn new(d: &'a FnDecl, b: ast::BodyId, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
         ClosureParts {
             decl: d,
             body: b,
@@ -172,9 +175,9 @@ impl<'a> FnLikeNode<'a> {
         }
     }
 
-    pub fn body(self) -> ast::ExprId {
+    pub fn body(self) -> ast::BodyId {
         self.handle(|i: ItemFnParts<'a>|  i.body,
-                    |_, _, _: &'a ast::MethodSig, _, body: ast::ExprId, _, _|  body,
+                    |_, _, _: &'a ast::MethodSig, _, body: ast::BodyId, _, _|  body,
                     |c: ClosureParts<'a>| c.body)
     }
 
@@ -227,7 +230,7 @@ impl<'a> FnLikeNode<'a> {
                   Name,
                   &'a ast::MethodSig,
                   Option<&'a ast::Visibility>,
-                  ast::ExprId,
+                  ast::BodyId,
                   Span,
                   &'a [Attribute])
                   -> A,
@@ -252,7 +255,7 @@ impl<'a> FnLikeNode<'a> {
                 _ => bug!("item FnLikeNode that is not fn-like"),
             },
             map::NodeTraitItem(ti) => match ti.node {
-                ast::MethodTraitItem(ref sig, Some(body)) => {
+                ast::TraitItemKind::Method(ref sig, ast::TraitMethod::Provided(body)) => {
                     method(ti.id, ti.name, sig, None, body, ti.span, &ti.attrs)
                 }
                 _ => bug!("trait method FnLikeNode that is not fn-like"),
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index 45988886a608a..a6ffe7cea5592 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -11,7 +11,6 @@
 use super::*;
 
 use hir::intravisit::{Visitor, NestedVisitorMap};
-use middle::cstore::InlinedItem;
 use std::iter::repeat;
 use syntax::ast::{NodeId, CRATE_NODE_ID};
 use syntax_pos::Span;
@@ -21,7 +20,7 @@ pub struct NodeCollector<'ast> {
     /// The crate
     pub krate: &'ast Crate,
     /// The node map
-    pub map: Vec<MapEntry<'ast>>,
+    pub(super) map: Vec<MapEntry<'ast>>,
     /// The parent of this node
     pub parent_node: NodeId,
     /// If true, completely ignore nested items. We set this when loading
@@ -43,11 +42,11 @@ impl<'ast> NodeCollector<'ast> {
         collector
     }
 
-    pub fn extend(krate: &'ast Crate,
-                  parent: &'ast InlinedItem,
-                  parent_node: NodeId,
-                  map: Vec<MapEntry<'ast>>)
-                  -> NodeCollector<'ast> {
+    pub(super) fn extend(krate: &'ast Crate,
+                         parent: &'ast InlinedItem,
+                         parent_node: NodeId,
+                         map: Vec<MapEntry<'ast>>)
+                         -> NodeCollector<'ast> {
         let mut collector = NodeCollector {
             krate: krate,
             map: map,
@@ -98,12 +97,22 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
         }
     }
 
+    fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
+        if !self.ignore_nested_items {
+            self.visit_trait_item(self.krate.trait_item(item_id))
+        }
+    }
+
     fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
-        self.visit_impl_item(self.krate.impl_item(item_id))
+        if !self.ignore_nested_items {
+            self.visit_impl_item(self.krate.impl_item(item_id))
+        }
     }
 
-    fn visit_body(&mut self, id: ExprId) {
-        self.visit_expr(self.krate.expr(id))
+    fn visit_nested_body(&mut self, id: BodyId) {
+        if !self.ignore_nested_items {
+            self.visit_body(self.krate.body(id))
+        }
     }
 
     fn visit_item(&mut self, i: &'ast Item) {
@@ -113,11 +122,6 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
 
         self.with_parent(i.id, |this| {
             match i.node {
-                ItemEnum(ref enum_definition, _) => {
-                    for v in &enum_definition.variants {
-                        this.insert(v.node.data.id(), NodeVariant(v));
-                    }
-                }
                 ItemStruct(ref struct_def, _) => {
                     // If this is a tuple-like struct, register the constructor.
                     if !struct_def.is_struct() {
@@ -209,7 +213,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
     }
 
     fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
-                b: ExprId, s: Span, id: NodeId) {
+                b: BodyId, s: Span, id: NodeId) {
         assert_eq!(self.parent_node, id);
         intravisit::walk_fn(self, fk, fd, b, s, id);
     }
@@ -243,6 +247,14 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
         self.insert_entry(macro_def.id, NotPresent);
     }
 
+    fn visit_variant(&mut self, v: &'ast Variant, g: &'ast Generics, item_id: NodeId) {
+        let id = v.node.data.id();
+        self.insert(id, NodeVariant(v));
+        self.with_parent(id, |this| {
+            intravisit::walk_variant(this, v, g, item_id);
+        });
+    }
+
     fn visit_struct_field(&mut self, field: &'ast StructField) {
         self.insert(field.id, NodeField(field));
         self.with_parent(field.id, |this| {
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 256aee342a3fc..be8780f39b104 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -16,7 +16,7 @@ use syntax::ext::hygiene::Mark;
 use syntax::visit;
 use syntax::symbol::{Symbol, keywords};
 
-/// Creates def ids for nodes in the HIR.
+/// Creates def ids for nodes in the AST.
 pub struct DefCollector<'a> {
     definitions: &'a mut Definitions,
     parent_def: Option<DefIndex>,
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 4f64670f48279..b28c5e80ea3c3 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -220,7 +220,6 @@ impl DefPath {
     }
 }
 
-
 #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub enum DefPathData {
     // Root: these should only be used for the root nodes, because
@@ -339,7 +338,7 @@ impl Definitions {
                 data,
                 self.table.def_key(self.node_to_def_index[&node_id]));
 
-        assert!(parent.is_some() ^ (data == DefPathData::CrateRoot));
+        assert_eq!(parent.is_some(), data != DefPathData::CrateRoot);
 
         // Find a unique DefKey. This basically means incrementing the disambiguator
         // until we get no match.
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 4546f6d8c27e6..27ebeea9ad91d 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -17,7 +17,6 @@ pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
 
 use dep_graph::{DepGraph, DepNode};
 
-use middle::cstore::InlinedItem;
 use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
 
 use syntax::abi::Abi;
@@ -26,7 +25,8 @@ use syntax::codemap::Spanned;
 use syntax_pos::Span;
 
 use hir::*;
-use hir::print as pprust;
+use hir::intravisit::Visitor;
+use hir::print::Nested;
 
 use arena::TypedArena;
 use std::cell::RefCell;
@@ -38,6 +38,15 @@ mod collector;
 mod def_collector;
 pub mod definitions;
 
+/// The data we save and restore about an inlined item or method.  This is not
+/// part of the AST that we parse from a file, but it becomes part of the tree
+/// that we trans.
+#[derive(Debug)]
+struct InlinedItem {
+    def_id: DefId,
+    body: Body,
+}
+
 #[derive(Copy, Clone, Debug)]
 pub enum Node<'ast> {
     NodeItem(&'ast Item),
@@ -60,14 +69,12 @@ pub enum Node<'ast> {
     NodeLifetime(&'ast Lifetime),
     NodeTyParam(&'ast TyParam),
     NodeVisibility(&'ast Visibility),
-
-    NodeInlinedItem(&'ast InlinedItem),
 }
 
 /// Represents an entry and its parent NodeID.
 /// The odd layout is to bring down the total size.
 #[derive(Copy, Debug)]
-pub enum MapEntry<'ast> {
+enum MapEntry<'ast> {
     /// Placeholder for holes in the map.
     NotPresent,
 
@@ -121,8 +128,6 @@ impl<'ast> MapEntry<'ast> {
             NodeLifetime(n) => EntryLifetime(p, n),
             NodeTyParam(n) => EntryTyParam(p, n),
             NodeVisibility(n) => EntryVisibility(p, n),
-
-            NodeInlinedItem(n) => RootInlinedParent(n),
         }
     }
 
@@ -171,10 +176,49 @@ impl<'ast> MapEntry<'ast> {
             EntryLifetime(_, n) => NodeLifetime(n),
             EntryTyParam(_, n) => NodeTyParam(n),
             EntryVisibility(_, n) => NodeVisibility(n),
-            RootInlinedParent(n) => NodeInlinedItem(n),
             _ => return None
         })
     }
+
+    fn is_body_owner(self, node_id: NodeId) -> bool {
+        match self {
+            EntryItem(_, item) => {
+                match item.node {
+                    ItemConst(_, body) |
+                    ItemStatic(.., body) |
+                    ItemFn(_, _, _, _, _, body) => body.node_id == node_id,
+                    _ => false
+                }
+            }
+
+            EntryTraitItem(_, item) => {
+                match item.node {
+                    TraitItemKind::Const(_, Some(body)) |
+                    TraitItemKind::Method(_, TraitMethod::Provided(body)) => {
+                        body.node_id == node_id
+                    }
+                    _ => false
+                }
+            }
+
+            EntryImplItem(_, item) => {
+                match item.node {
+                    ImplItemKind::Const(_, body) |
+                    ImplItemKind::Method(_, body) => body.node_id == node_id,
+                    _ => false
+                }
+            }
+
+            EntryExpr(_, expr) => {
+                match expr.node {
+                    ExprClosure(.., body, _) => body.node_id == node_id,
+                    _ => false
+                }
+            }
+
+            _ => false
+        }
+    }
 }
 
 /// Stores a crate and any number of inlined items from other crates.
@@ -250,38 +294,34 @@ impl<'ast> Map<'ast> {
         if !self.is_inlined_node_id(id) {
             let mut last_expr = None;
             loop {
-                match map[id.as_usize()] {
-                    EntryItem(_, item) => {
-                        assert_eq!(id, item.id);
-                        let def_id = self.local_def_id(id);
-
+                let entry = map[id.as_usize()];
+                match entry {
+                    EntryItem(..) |
+                    EntryTraitItem(..) |
+                    EntryImplItem(..) => {
                         if let Some(last_id) = last_expr {
-                            // The body of the item may have a separate dep node
-                            // (Note that trait items don't currently have
-                            // their own dep node, so there's also just one
-                            // HirBody node for all the items)
-                            if self.is_body(last_id, item) {
+                            // The body may have a separate dep node
+                            if entry.is_body_owner(last_id) {
+                                let def_id = self.local_def_id(id);
                                 return DepNode::HirBody(def_id);
                             }
                         }
-                        return DepNode::Hir(def_id);
+                        return DepNode::Hir(self.local_def_id(id));
                     }
 
-                    EntryImplItem(_, item) => {
-                        let def_id = self.local_def_id(id);
+                    EntryVariant(p, v) => {
+                        id = p;
 
-                        if let Some(last_id) = last_expr {
-                            // The body of the item may have a separate dep node
-                            if self.is_impl_item_body(last_id, item) {
+                        if last_expr.is_some() {
+                            if v.node.disr_expr.map(|e| e.node_id) == last_expr {
+                                // The enum parent holds both Hir and HirBody nodes.
+                                let def_id = self.local_def_id(id);
                                 return DepNode::HirBody(def_id);
                             }
                         }
-                        return DepNode::Hir(def_id);
                     }
 
                     EntryForeignItem(p, _) |
-                    EntryTraitItem(p, _) |
-                    EntryVariant(p, _) |
                     EntryField(p, _) |
                     EntryStmt(p, _) |
                     EntryTy(p, _) |
@@ -308,7 +348,7 @@ impl<'ast> Map<'ast> {
                         bug!("node {} has inlined ancestor but is not inlined", id0),
 
                     NotPresent =>
-                        // Some nodes, notably struct fields, are not
+                        // Some nodes, notably macro definitions, are not
                         // present in the map for whatever reason, but
                         // they *do* have def-ids. So if we encounter an
                         // empty hole, check for that case.
@@ -358,29 +398,6 @@ impl<'ast> Map<'ast> {
         }
     }
 
-    fn is_body(&self, node_id: NodeId, item: &Item) -> bool {
-        match item.node {
-            ItemFn(_, _, _, _, _, body) => body.node_id() == node_id,
-            // Since trait items currently don't get their own dep nodes,
-            // we check here whether node_id is the body of any of the items.
-            // If they get their own dep nodes, this can go away
-            ItemTrait(_, _, _, ref trait_items) => {
-                trait_items.iter().any(|trait_item| { match trait_item.node {
-                    MethodTraitItem(_, Some(body)) => body.node_id() == node_id,
-                    _ => false
-                }})
-            }
-            _ => false
-        }
-    }
-
-    fn is_impl_item_body(&self, node_id: NodeId, item: &ImplItem) -> bool {
-        match item.node {
-            ImplItemKind::Method(_, body) => body.node_id() == node_id,
-            _ => false
-        }
-    }
-
     pub fn num_local_def_ids(&self) -> usize {
         self.definitions.len()
     }
@@ -436,6 +453,14 @@ impl<'ast> Map<'ast> {
         self.forest.krate()
     }
 
+    pub fn trait_item(&self, id: TraitItemId) -> &'ast TraitItem {
+        self.read(id.node_id);
+
+        // NB: intentionally bypass `self.forest.krate()` so that we
+        // do not trigger a read of the whole krate here
+        self.forest.krate.trait_item(id)
+    }
+
     pub fn impl_item(&self, id: ImplItemId) -> &'ast ImplItem {
         self.read(id.node_id);
 
@@ -444,6 +469,31 @@ impl<'ast> Map<'ast> {
         self.forest.krate.impl_item(id)
     }
 
+    pub fn body(&self, id: BodyId) -> &'ast Body {
+        self.read(id.node_id);
+
+        // NB: intentionally bypass `self.forest.krate()` so that we
+        // do not trigger a read of the whole krate here
+        self.forest.krate.body(id)
+    }
+
+    /// Returns the `NodeId` that corresponds to the definition of
+    /// which this is the body of, i.e. a `fn`, `const` or `static`
+    /// item (possibly associated), or a closure, or the body itself
+    /// for embedded constant expressions (e.g. `N` in `[T; N]`).
+    pub fn body_owner(&self, BodyId { node_id }: BodyId) -> NodeId {
+        let parent = self.get_parent_node(node_id);
+        if self.map.borrow()[parent.as_usize()].is_body_owner(node_id) {
+            parent
+        } else {
+            node_id
+        }
+    }
+
+    pub fn body_owner_def_id(&self, id: BodyId) -> DefId {
+        self.local_def_id(self.body_owner(id))
+    }
+
     /// Get the attributes on the krate. This is preferable to
     /// invoking `krate.attrs` because it registers a tighter
     /// dep-graph access.
@@ -687,17 +737,13 @@ impl<'ast> Map<'ast> {
         }
     }
 
-    pub fn expect_inlined_item(&self, id: NodeId) -> &'ast InlinedItem {
+    pub fn expect_inlined_body(&self, id: NodeId) -> &'ast Body {
         match self.find_entry(id) {
-            Some(RootInlinedParent(inlined_item)) => inlined_item,
+            Some(RootInlinedParent(inlined_item)) => &inlined_item.body,
             _ => bug!("expected inlined item, found {}", self.node_to_string(id)),
         }
     }
 
-    pub fn expr(&self, id: ExprId) -> &'ast Expr {
-        self.expect_expr(id.node_id())
-    }
-
     /// Returns the name associated with the given NodeId's AST.
     pub fn name(&self, id: NodeId) -> Name {
         match self.get(id) {
@@ -778,7 +824,7 @@ impl<'ast> Map<'ast> {
             Some(EntryVisibility(_, v)) => bug!("unexpected Visibility {:?}", v),
 
             Some(RootCrate) => self.forest.krate.span,
-            Some(RootInlinedParent(parent)) => parent.body.span,
+            Some(RootInlinedParent(parent)) => parent.body.value.span,
             Some(NotPresent) | None => {
                 bug!("hir::map::Map::span: id not in map: {:?}", id)
             }
@@ -796,6 +842,10 @@ impl<'ast> Map<'ast> {
     pub fn node_to_user_string(&self, id: NodeId) -> String {
         node_id_to_string(self, id, false)
     }
+
+    pub fn node_to_pretty_string(&self, id: NodeId) -> String {
+        print::to_string(self, |s| s.print_node(self.get(id)))
+    }
 }
 
 pub struct NodesMatchingSuffix<'a, 'ast:'a> {
@@ -934,33 +984,47 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest,
     }
 }
 
-/// Used for items loaded from external crate that are being inlined into this
+/// Used for bodies loaded from external crate that are being inlined into this
 /// crate.
-pub fn map_decoded_item<'ast>(map: &Map<'ast>,
-                              ii: InlinedItem,
-                              ii_parent_id: NodeId)
-                              -> &'ast InlinedItem {
+pub fn map_decoded_body<'ast>(map: &Map<'ast>,
+                              def_id: DefId,
+                              body: Body,
+                              parent_id: NodeId)
+                              -> &'ast Body {
     let _ignore = map.forest.dep_graph.in_ignore();
 
-    let ii = map.forest.inlined_items.alloc(ii);
+    let ii = map.forest.inlined_items.alloc(InlinedItem {
+        def_id: def_id,
+        body: body
+    });
 
     let mut collector = NodeCollector::extend(map.krate(),
                                               ii,
-                                              ii_parent_id,
+                                              parent_id,
                                               mem::replace(&mut *map.map.borrow_mut(), vec![]));
-    ii.visit(&mut collector);
+    collector.visit_body(&ii.body);
     *map.map.borrow_mut() = collector.map;
 
-    ii
+    &ii.body
 }
 
-pub trait NodePrinter {
-    fn print_node(&mut self, node: &Node) -> io::Result<()>;
+/// Identical to the `PpAnn` implementation for `hir::Crate`,
+/// except it avoids creating a dependency on the whole crate.
+impl<'ast> print::PpAnn for Map<'ast> {
+    fn nested(&self, state: &mut print::State, nested: print::Nested) -> io::Result<()> {
+        match nested {
+            Nested::Item(id) => state.print_item(self.expect_item(id.id)),
+            Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)),
+            Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)),
+            Nested::Body(id) => state.print_expr(&self.body(id).value),
+            Nested::BodyArgPat(id, i) => state.print_pat(&self.body(id).arguments[i].pat)
+        }
+    }
 }
 
-impl<'a> NodePrinter for pprust::State<'a> {
-    fn print_node(&mut self, node: &Node) -> io::Result<()> {
-        match *node {
+impl<'a> print::State<'a> {
+    pub fn print_node(&mut self, node: Node) -> io::Result<()> {
+        match node {
             NodeItem(a)        => self.print_item(&a),
             NodeForeignItem(a) => self.print_foreign_item(&a),
             NodeTraitItem(a)   => self.print_trait_item(a),
@@ -970,8 +1034,17 @@ impl<'a> NodePrinter for pprust::State<'a> {
             NodeStmt(a)        => self.print_stmt(&a),
             NodeTy(a)          => self.print_type(&a),
             NodeTraitRef(a)    => self.print_trait_ref(&a),
+            NodeLocal(a)       |
             NodePat(a)         => self.print_pat(&a),
-            NodeBlock(a)       => self.print_block(&a),
+            NodeBlock(a)       => {
+                use syntax::print::pprust::PrintState;
+
+                // containing cbox, will be closed by print-block at }
+                self.cbox(print::indent_unit)?;
+                // head-ibox, will be closed by print-block after {
+                self.ibox(0)?;
+                self.print_block(&a)
+            }
             NodeLifetime(a)    => self.print_lifetime(&a),
             NodeVisibility(a)  => self.print_visibility(&a),
             NodeTyParam(_)     => bug!("cannot print TyParam"),
@@ -979,10 +1052,7 @@ impl<'a> NodePrinter for pprust::State<'a> {
             // these cases do not carry enough information in the
             // ast_map to reconstruct their full structure for pretty
             // printing.
-            NodeLocal(_)       => bug!("cannot print isolated Local"),
             NodeStructCtor(_)  => bug!("cannot print isolated StructCtor"),
-
-            NodeInlinedItem(_) => bug!("cannot print inlined item"),
         }
     }
 }
@@ -1045,9 +1115,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
         }
         Some(NodeTraitItem(ti)) => {
             let kind = match ti.node {
-                ConstTraitItem(..) => "assoc constant",
-                MethodTraitItem(..) => "trait method",
-                TypeTraitItem(..) => "assoc type",
+                TraitItemKind::Const(..) => "assoc constant",
+                TraitItemKind::Method(..) => "trait method",
+                TraitItemKind::Type(..) => "assoc type",
             };
 
             format!("{} {} in {}{}", kind, ti.name, path_str(), id_str)
@@ -1062,33 +1132,32 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
                     field.name,
                     path_str(), id_str)
         }
-        Some(NodeExpr(ref expr)) => {
-            format!("expr {}{}", pprust::expr_to_string(&expr), id_str)
+        Some(NodeExpr(_)) => {
+            format!("expr {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(NodeStmt(ref stmt)) => {
-            format!("stmt {}{}", pprust::stmt_to_string(&stmt), id_str)
+        Some(NodeStmt(_)) => {
+            format!("stmt {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(NodeTy(ref ty)) => {
-            format!("type {}{}", pprust::ty_to_string(&ty), id_str)
+        Some(NodeTy(_)) => {
+            format!("type {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(NodeTraitRef(ref tr)) => {
-            format!("trait_ref {}{}", pprust::path_to_string(&tr.path), id_str)
+        Some(NodeTraitRef(_)) => {
+            format!("trait_ref {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(NodeLocal(ref pat)) => {
-            format!("local {}{}", pprust::pat_to_string(&pat), id_str)
+        Some(NodeLocal(_)) => {
+            format!("local {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(NodePat(ref pat)) => {
-            format!("pat {}{}", pprust::pat_to_string(&pat), id_str)
+        Some(NodePat(_)) => {
+            format!("pat {}{}", map.node_to_pretty_string(id), id_str)
         }
-        Some(NodeBlock(ref block)) => {
-            format!("block {}{}", pprust::block_to_string(&block), id_str)
+        Some(NodeBlock(_)) => {
+            format!("block {}{}", map.node_to_pretty_string(id), id_str)
         }
         Some(NodeStructCtor(_)) => {
             format!("struct_ctor {}{}", path_str(), id_str)
         }
-        Some(NodeLifetime(ref l)) => {
-            format!("lifetime {}{}",
-                    pprust::lifetime_to_string(&l), id_str)
+        Some(NodeLifetime(_)) => {
+            format!("lifetime {}{}", map.node_to_pretty_string(id), id_str)
         }
         Some(NodeTyParam(ref ty_param)) => {
             format!("typaram {:?}{}", ty_param, id_str)
@@ -1096,9 +1165,6 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
         Some(NodeVisibility(ref vis)) => {
             format!("visibility {:?}{}", vis, id_str)
         }
-        Some(NodeInlinedItem(_)) => {
-            format!("inlined item {}", id_str)
-        }
         None => {
             format!("unknown node{}", id_str)
         }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 4eee76d466ac1..9149da459c26e 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -22,7 +22,6 @@ pub use self::Item_::*;
 pub use self::Mutability::*;
 pub use self::PrimTy::*;
 pub use self::Stmt_::*;
-pub use self::TraitItem_::*;
 pub use self::Ty_::*;
 pub use self::TyParamBound::*;
 pub use self::UnOp::*;
@@ -32,11 +31,10 @@ pub use self::PathParameters::*;
 
 use hir::def::Def;
 use hir::def_id::DefId;
-use util::nodemap::{NodeMap, FxHashSet};
-use rustc_data_structures::fnv::FnvHashMap;
+use util::nodemap::{NodeMap, FxHashMap, FxHashSet};
 
-use syntax_pos::{mk_sp, Span, ExpnId, DUMMY_SP};
-use syntax::codemap::{self, respan, Spanned};
+use syntax_pos::{Span, ExpnId, DUMMY_SP};
+use syntax::codemap::{self, Spanned};
 use syntax::abi::Abi;
 use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect};
 use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
@@ -87,7 +85,7 @@ impl fmt::Debug for Lifetime {
         write!(f,
                "lifetime({}: {})",
                self.id,
-               print::lifetime_to_string(self))
+               print::to_string(print::NO_ANN, |s| s.print_lifetime(self)))
     }
 }
 
@@ -119,13 +117,8 @@ impl Path {
 
 impl fmt::Debug for Path {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "path({})", print::path_to_string(self))
-    }
-}
-
-impl fmt::Display for Path {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", print::path_to_string(self))
+        write!(f, "path({})",
+               print::to_string(print::NO_ANN, |s| s.print_path(self, false)))
     }
 }
 
@@ -431,8 +424,9 @@ pub struct Crate {
     // slightly different results.
     pub items: BTreeMap<NodeId, Item>,
 
+    pub trait_items: BTreeMap<TraitItemId, TraitItem>,
     pub impl_items: BTreeMap<ImplItemId, ImplItem>,
-    pub exprs: FnvHashMap<ExprId, Expr>,
+    pub bodies: FxHashMap<BodyId, Body>,
 }
 
 impl Crate {
@@ -440,6 +434,10 @@ impl Crate {
         &self.items[&id]
     }
 
+    pub fn trait_item(&self, id: TraitItemId) -> &TraitItem {
+        &self.trait_items[&id]
+    }
+
     pub fn impl_item(&self, id: ImplItemId) -> &ImplItem {
         &self.impl_items[&id]
     }
@@ -459,13 +457,17 @@ impl Crate {
             visitor.visit_item(item);
         }
 
+        for (_, trait_item) in &self.trait_items {
+            visitor.visit_trait_item(trait_item);
+        }
+
         for (_, impl_item) in &self.impl_items {
             visitor.visit_impl_item(impl_item);
         }
     }
 
-    pub fn expr(&self, id: ExprId) -> &Expr {
-        &self.exprs[&id]
+    pub fn body(&self, id: BodyId) -> &Body {
+        &self.bodies[&id]
     }
 }
 
@@ -503,7 +505,8 @@ pub struct Pat {
 
 impl fmt::Debug for Pat {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "pat({}: {})", self.id, print::pat_to_string(self))
+        write!(f, "pat({}: {})", self.id,
+               print::to_string(print::NO_ANN, |s| s.print_pat(self)))
     }
 }
 
@@ -755,7 +758,7 @@ impl fmt::Debug for Stmt_ {
         write!(f,
                "stmt({}: {})",
                spanned.node.id(),
-               print::stmt_to_string(&spanned))
+               print::to_string(print::NO_ANN, |s| s.print_stmt(&spanned)))
     }
 }
 
@@ -853,12 +856,23 @@ pub enum UnsafeSource {
     UserProvided,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct ExprId(NodeId);
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct BodyId {
+    pub node_id: NodeId,
+}
 
-impl ExprId {
-    pub fn node_id(self) -> NodeId {
-        self.0
+/// The body of a function or constant value.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct Body {
+    pub arguments: HirVec<Arg>,
+    pub value: Expr
+}
+
+impl Body {
+    pub fn id(&self) -> BodyId {
+        BodyId {
+            node_id: self.value.id
+        }
     }
 }
 
@@ -871,15 +885,10 @@ pub struct Expr {
     pub attrs: ThinVec<Attribute>,
 }
 
-impl Expr {
-    pub fn expr_id(&self) -> ExprId {
-        ExprId(self.id)
-    }
-}
-
 impl fmt::Debug for Expr {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "expr({}: {})", self.id, print::expr_to_string(self))
+        write!(f, "expr({}: {})", self.id,
+               print::to_string(print::NO_ANN, |s| s.print_expr(self)))
     }
 }
 
@@ -936,7 +945,7 @@ pub enum Expr_ {
     /// A closure (for example, `move |a, b, c| {a + b + c}`).
     ///
     /// The final span is the span of the argument block `|...|`
-    ExprClosure(CaptureClause, P<FnDecl>, ExprId, Span),
+    ExprClosure(CaptureClause, P<FnDecl>, BodyId, Span),
     /// A block (`{ ... }`)
     ExprBlock(P<Block>),
 
@@ -980,7 +989,7 @@ pub enum Expr_ {
     ///
     /// For example, `[1; 5]`. The first expression is the element
     /// to be repeated; the second is the number of times to repeat it.
-    ExprRepeat(P<Expr>, P<Expr>),
+    ExprRepeat(P<Expr>, BodyId),
 }
 
 /// Optionally `Self`-qualified value/type path or associated extension.
@@ -1003,12 +1012,6 @@ pub enum QPath {
     TypeRelative(P<Ty>, P<PathSegment>)
 }
 
-impl fmt::Display for QPath {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", print::qpath_to_string(self))
-    }
-}
-
 /// Hints at the original code for a `match _ { .. }`
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 pub enum MatchSource {
@@ -1070,6 +1073,14 @@ pub struct MethodSig {
     pub generics: Generics,
 }
 
+// The bodies for items are stored "out of line", in a separate
+// hashmap in the `Crate`. Here we just record the node-id of the item
+// so it can fetched later.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct TraitItemId {
+    pub node_id: NodeId,
+}
+
 /// Represents an item declaration within a trait declaration,
 /// possibly including a default implementation. A trait item is
 /// either required (meaning it doesn't have an implementation, just a
@@ -1079,21 +1090,31 @@ pub struct TraitItem {
     pub id: NodeId,
     pub name: Name,
     pub attrs: HirVec<Attribute>,
-    pub node: TraitItem_,
+    pub node: TraitItemKind,
     pub span: Span,
 }
 
+/// A trait method's body (or just argument names).
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum TraitMethod {
+    /// No default body in the trait, just a signature.
+    Required(HirVec<Spanned<Name>>),
+
+    /// Both signature and body are provided in the trait.
+    Provided(BodyId),
+}
+
 /// Represents a trait method or associated constant or type
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum TraitItem_ {
+pub enum TraitItemKind {
     /// An associated constant with an optional value (otherwise `impl`s
     /// must contain a value)
-    ConstTraitItem(P<Ty>, Option<P<Expr>>),
+    Const(P<Ty>, Option<BodyId>),
     /// A method with an optional body
-    MethodTraitItem(MethodSig, Option<ExprId>),
+    Method(MethodSig, TraitMethod),
     /// An associated type with (possibly empty) bounds and optional concrete
     /// type
-    TypeTraitItem(TyParamBounds, Option<P<Ty>>),
+    Type(TyParamBounds, Option<P<Ty>>),
 }
 
 // The bodies for items are stored "out of line", in a separate
@@ -1121,9 +1142,9 @@ pub struct ImplItem {
 pub enum ImplItemKind {
     /// An associated constant of the given type, set to the constant result
     /// of the expression
-    Const(P<Ty>, P<Expr>),
+    Const(P<Ty>, BodyId),
     /// A method implementation with the given signature and body
-    Method(MethodSig, ExprId),
+    Method(MethodSig, BodyId),
     /// An associated type
     Type(P<Ty>),
 }
@@ -1147,7 +1168,8 @@ pub struct Ty {
 
 impl fmt::Debug for Ty {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "type({})", print::ty_to_string(self))
+        write!(f, "type({})",
+               print::to_string(print::NO_ANN, |s| s.print_type(self)))
     }
 }
 
@@ -1176,7 +1198,7 @@ pub enum Ty_ {
     /// A variable length slice (`[T]`)
     TySlice(P<Ty>),
     /// A fixed length array (`[T; n]`)
-    TyArray(P<Ty>, P<Expr>),
+    TyArray(P<Ty>, BodyId),
     /// A raw pointer (`*const T` or `*mut T`)
     TyPtr(MutTy),
     /// A reference (`&'a T` or `&'a mut T`)
@@ -1200,7 +1222,7 @@ pub enum Ty_ {
     /// An `impl TraitA+TraitB` type.
     TyImplTrait(TyParamBounds),
     /// Unused for now
-    TyTypeof(P<Expr>),
+    TyTypeof(BodyId),
     /// TyInfer means the type should be inferred instead of it having been
     /// specified. This can appear anywhere in a type.
     TyInfer,
@@ -1229,67 +1251,18 @@ pub struct InlineAsm {
 /// represents an argument in a function header
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct Arg {
-    pub ty: P<Ty>,
     pub pat: P<Pat>,
     pub id: NodeId,
 }
 
-/// Alternative representation for `Arg`s describing `self` parameter of methods.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum SelfKind {
-    /// `self`, `mut self`
-    Value(Mutability),
-    /// `&'lt self`, `&'lt mut self`
-    Region(Option<Lifetime>, Mutability),
-    /// `self: TYPE`, `mut self: TYPE`
-    Explicit(P<Ty>, Mutability),
-}
-
-pub type ExplicitSelf = Spanned<SelfKind>;
-
-impl Arg {
-    pub fn to_self(&self) -> Option<ExplicitSelf> {
-        if let PatKind::Binding(BindByValue(mutbl), _, name, _) = self.pat.node {
-            if name.node == keywords::SelfValue.name() {
-                return match self.ty.node {
-                    TyInfer => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
-                    TyRptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyInfer => {
-                        Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
-                    }
-                    _ => Some(respan(mk_sp(self.pat.span.lo, self.ty.span.hi),
-                                     SelfKind::Explicit(self.ty.clone(), mutbl)))
-                }
-            }
-        }
-        None
-    }
-
-    pub fn is_self(&self) -> bool {
-        if let PatKind::Binding(_, _, name, _) = self.pat.node {
-            name.node == keywords::SelfValue.name()
-        } else {
-            false
-        }
-    }
-}
-
 /// Represents the header (not the body) of a function declaration
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct FnDecl {
-    pub inputs: HirVec<Arg>,
+    pub inputs: HirVec<P<Ty>>,
     pub output: FunctionRetTy,
     pub variadic: bool,
 }
 
-impl FnDecl {
-    pub fn get_self(&self) -> Option<ExplicitSelf> {
-        self.inputs.get(0).and_then(Arg::to_self)
-    }
-    pub fn has_self(&self) -> bool {
-        self.inputs.get(0).map(Arg::is_self).unwrap_or(false)
-    }
-}
-
 #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum Unsafety {
     Unsafe,
@@ -1403,7 +1376,7 @@ pub struct Variant_ {
     pub attrs: HirVec<Attribute>,
     pub data: VariantData,
     /// Explicit discriminant, eg `Foo = 1`
-    pub disr_expr: Option<P<Expr>>,
+    pub disr_expr: Option<BodyId>,
 }
 
 pub type Variant = Spanned<Variant_>;
@@ -1562,11 +1535,11 @@ pub enum Item_ {
     ItemUse(P<Path>, UseKind),
 
     /// A `static` item
-    ItemStatic(P<Ty>, Mutability, P<Expr>),
+    ItemStatic(P<Ty>, Mutability, BodyId),
     /// A `const` item
-    ItemConst(P<Ty>, P<Expr>),
+    ItemConst(P<Ty>, BodyId),
     /// A function declaration
-    ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, ExprId),
+    ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, BodyId),
     /// A module
     ItemMod(Mod),
     /// An external module
@@ -1580,7 +1553,7 @@ pub enum Item_ {
     /// A union definition, e.g. `union Foo<A, B> {x: A, y: B}`
     ItemUnion(VariantData, Generics),
     /// Represents a Trait Declaration
-    ItemTrait(Unsafety, Generics, TyParamBounds, HirVec<TraitItem>),
+    ItemTrait(Unsafety, Generics, TyParamBounds, HirVec<TraitItemRef>),
 
     // Default trait implementations
     ///
@@ -1616,6 +1589,21 @@ impl Item_ {
     }
 }
 
+/// A reference from an trait to one of its associated items. This
+/// contains the item's id, naturally, but also the item's name and
+/// some other high-level details (like whether it is an associated
+/// type or method, and whether it is public). This allows other
+/// passes to find the impl they want without loading the id (which
+/// means fewer edges in the incremental compilation graph).
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct TraitItemRef {
+    pub id: TraitItemId,
+    pub name: Name,
+    pub kind: AssociatedItemKind,
+    pub span: Span,
+    pub defaultness: Defaultness,
+}
+
 /// A reference from an impl to one of its associated items. This
 /// contains the item's id, naturally, but also the item's name and
 /// some other high-level details (like whether it is an associated
@@ -1653,7 +1641,7 @@ pub struct ForeignItem {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum ForeignItem_ {
     /// A foreign function
-    ForeignItemFn(P<FnDecl>, Generics),
+    ForeignItemFn(P<FnDecl>, HirVec<Spanned<Name>>, Generics),
     /// A foreign static item (`static ext: u8`), with optional mutability
     /// (the boolean is true when mutable)
     ForeignItemStatic(P<Ty>, bool),
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 100e344d94180..18fa6836b5108 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -13,7 +13,6 @@ pub use self::AnnNode::*;
 use syntax::abi::Abi;
 use syntax::ast;
 use syntax::codemap::{CodeMap, Spanned};
-use syntax::parse::token::{self, BinOpToken};
 use syntax::parse::lexer::comments;
 use syntax::print::pp::{self, break_offset, word, space, hardbreak};
 use syntax::print::pp::{Breaks, eof};
@@ -25,7 +24,7 @@ use syntax_pos::{self, BytePos};
 use errors;
 
 use hir;
-use hir::{Crate, PatKind, RegionTyParamBound, SelfKind, TraitTyParamBound, TraitBoundModifier};
+use hir::{PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
 
 use std::io::{self, Write, Read};
 
@@ -38,7 +37,18 @@ pub enum AnnNode<'a> {
     NodePat(&'a hir::Pat),
 }
 
+pub enum Nested {
+    Item(hir::ItemId),
+    TraitItem(hir::TraitItemId),
+    ImplItem(hir::ImplItemId),
+    Body(hir::BodyId),
+    BodyArgPat(hir::BodyId, usize)
+}
+
 pub trait PpAnn {
+    fn nested(&self, _state: &mut State, _nested: Nested) -> io::Result<()> {
+        Ok(())
+    }
     fn pre(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> {
         Ok(())
     }
@@ -47,14 +57,23 @@ pub trait PpAnn {
     }
 }
 
-#[derive(Copy, Clone)]
 pub struct NoAnn;
-
 impl PpAnn for NoAnn {}
+pub const NO_ANN: &'static PpAnn = &NoAnn;
 
+impl PpAnn for hir::Crate {
+    fn nested(&self, state: &mut State, nested: Nested) -> io::Result<()> {
+        match nested {
+            Nested::Item(id) => state.print_item(self.item(id.id)),
+            Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)),
+            Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)),
+            Nested::Body(id) => state.print_expr(&self.body(id).value),
+            Nested::BodyArgPat(id, i) => state.print_pat(&self.body(id).arguments[i].pat)
+        }
+    }
+}
 
 pub struct State<'a> {
-    krate: Option<&'a Crate>,
     pub s: pp::Printer<'a>,
     cm: Option<&'a CodeMap>,
     comments: Option<Vec<comments::Comment>>,
@@ -86,30 +105,6 @@ impl<'a> PrintState<'a> for State<'a> {
     }
 }
 
-pub fn rust_printer<'a>(writer: Box<Write + 'a>, krate: Option<&'a Crate>) -> State<'a> {
-    static NO_ANN: NoAnn = NoAnn;
-    rust_printer_annotated(writer, &NO_ANN, krate)
-}
-
-pub fn rust_printer_annotated<'a>(writer: Box<Write + 'a>,
-                                  ann: &'a PpAnn,
-                                  krate: Option<&'a Crate>)
-                                  -> State<'a> {
-    State {
-        krate: krate,
-        s: pp::mk_printer(writer, default_columns),
-        cm: None,
-        comments: None,
-        literals: None,
-        cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral {
-            cur_cmnt: 0,
-            cur_lit: 0,
-        },
-        boxes: Vec::new(),
-        ann: ann,
-    }
-}
-
 #[allow(non_upper_case_globals)]
 pub const indent_unit: usize = 4;
 
@@ -130,7 +125,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap,
                        is_expanded: bool)
                        -> io::Result<()> {
     let mut s = State::new_from_input(cm, span_diagnostic, filename, input,
-                                      out, ann, is_expanded, Some(krate));
+                                      out, ann, is_expanded);
 
     // When printing the AST, we sometimes need to inject `#[no_std]` here.
     // Since you can't compile the HIR, it's not necessary.
@@ -147,8 +142,7 @@ impl<'a> State<'a> {
                           input: &mut Read,
                           out: Box<Write + 'a>,
                           ann: &'a PpAnn,
-                          is_expanded: bool,
-                          krate: Option<&'a Crate>)
+                          is_expanded: bool)
                           -> State<'a> {
         let (cmnts, lits) = comments::gather_comments_and_literals(span_diagnostic,
                                                                    filename,
@@ -165,19 +159,16 @@ impl<'a> State<'a> {
                        None
                    } else {
                        Some(lits)
-                   },
-                   krate)
+                   })
     }
 
     pub fn new(cm: &'a CodeMap,
                out: Box<Write + 'a>,
                ann: &'a PpAnn,
                comments: Option<Vec<comments::Comment>>,
-               literals: Option<Vec<comments::Literal>>,
-               krate: Option<&'a Crate>)
+               literals: Option<Vec<comments::Literal>>)
                -> State<'a> {
         State {
-            krate: krate,
             s: pp::mk_printer(out, default_columns),
             cm: Some(cm),
             comments: comments.clone(),
@@ -192,144 +183,36 @@ impl<'a> State<'a> {
     }
 }
 
-pub fn to_string<F>(f: F) -> String
+pub fn to_string<F>(ann: &PpAnn, f: F) -> String
     where F: FnOnce(&mut State) -> io::Result<()>
 {
     let mut wr = Vec::new();
     {
-        let mut printer = rust_printer(Box::new(&mut wr), None);
+        let mut printer = State {
+            s: pp::mk_printer(Box::new(&mut wr), default_columns),
+            cm: None,
+            comments: None,
+            literals: None,
+            cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral {
+                cur_cmnt: 0,
+                cur_lit: 0,
+            },
+            boxes: Vec::new(),
+            ann: ann,
+        };
         f(&mut printer).unwrap();
         eof(&mut printer.s).unwrap();
     }
     String::from_utf8(wr).unwrap()
 }
 
-pub fn binop_to_string(op: BinOpToken) -> &'static str {
-    match op {
-        token::Plus => "+",
-        token::Minus => "-",
-        token::Star => "*",
-        token::Slash => "/",
-        token::Percent => "%",
-        token::Caret => "^",
-        token::And => "&",
-        token::Or => "|",
-        token::Shl => "<<",
-        token::Shr => ">>",
-    }
-}
-
-pub fn ty_to_string(ty: &hir::Ty) -> String {
-    to_string(|s| s.print_type(ty))
-}
-
-pub fn bounds_to_string(bounds: &[hir::TyParamBound]) -> String {
-    to_string(|s| s.print_bounds("", bounds))
-}
-
-pub fn pat_to_string(pat: &hir::Pat) -> String {
-    to_string(|s| s.print_pat(pat))
-}
-
-pub fn arm_to_string(arm: &hir::Arm) -> String {
-    to_string(|s| s.print_arm(arm))
-}
-
-pub fn expr_to_string(e: &hir::Expr) -> String {
-    to_string(|s| s.print_expr(e))
-}
-
-pub fn lifetime_to_string(e: &hir::Lifetime) -> String {
-    to_string(|s| s.print_lifetime(e))
-}
-
-pub fn stmt_to_string(stmt: &hir::Stmt) -> String {
-    to_string(|s| s.print_stmt(stmt))
-}
-
-pub fn item_to_string(i: &hir::Item) -> String {
-    to_string(|s| s.print_item(i))
-}
-
-pub fn impl_item_to_string(i: &hir::ImplItem) -> String {
-    to_string(|s| s.print_impl_item(i))
-}
-
-pub fn trait_item_to_string(i: &hir::TraitItem) -> String {
-    to_string(|s| s.print_trait_item(i))
-}
-
-pub fn generics_to_string(generics: &hir::Generics) -> String {
-    to_string(|s| s.print_generics(generics))
-}
-
-pub fn where_clause_to_string(i: &hir::WhereClause) -> String {
-    to_string(|s| s.print_where_clause(i))
-}
-
-pub fn fn_block_to_string(p: &hir::FnDecl) -> String {
-    to_string(|s| s.print_fn_block_args(p))
-}
-
-pub fn path_to_string(p: &hir::Path) -> String {
-    to_string(|s| s.print_path(p, false))
-}
-
-pub fn qpath_to_string(p: &hir::QPath) -> String {
-    to_string(|s| s.print_qpath(p, false))
-}
-
-pub fn name_to_string(name: ast::Name) -> String {
-    to_string(|s| s.print_name(name))
-}
-
-pub fn fun_to_string(decl: &hir::FnDecl,
-                     unsafety: hir::Unsafety,
-                     constness: hir::Constness,
-                     name: ast::Name,
-                     generics: &hir::Generics)
-                     -> String {
-    to_string(|s| {
-        s.head("")?;
-        s.print_fn(decl,
-                   unsafety,
-                   constness,
-                   Abi::Rust,
-                   Some(name),
-                   generics,
-                   &hir::Inherited)?;
-        s.end()?; // Close the head box
-        s.end() // Close the outer box
+pub fn visibility_qualified(vis: &hir::Visibility, w: &str) -> String {
+    to_string(NO_ANN, |s| {
+        s.print_visibility(vis)?;
+        word(&mut s.s, w)
     })
 }
 
-pub fn block_to_string(blk: &hir::Block) -> String {
-    to_string(|s| {
-        // containing cbox, will be closed by print-block at }
-        s.cbox(indent_unit)?;
-        // head-ibox, will be closed by print-block after {
-        s.ibox(0)?;
-        s.print_block(blk)
-    })
-}
-
-pub fn variant_to_string(var: &hir::Variant) -> String {
-    to_string(|s| s.print_variant(var))
-}
-
-pub fn arg_to_string(arg: &hir::Arg) -> String {
-    to_string(|s| s.print_arg(arg, false))
-}
-
-pub fn visibility_qualified(vis: &hir::Visibility, s: &str) -> String {
-    match *vis {
-        hir::Public => format!("pub {}", s),
-        hir::Visibility::Crate => format!("pub(crate) {}", s),
-        hir::Visibility::Restricted { ref path, .. } => format!("pub({}) {}", path, s),
-        hir::Inherited => s.to_string(),
-    }
-}
-
 fn needs_parentheses(expr: &hir::Expr) -> bool {
     match expr.node {
         hir::ExprAssign(..) |
@@ -462,8 +345,8 @@ impl<'a> State<'a> {
 
     pub fn print_mod(&mut self, _mod: &hir::Mod, attrs: &[ast::Attribute]) -> io::Result<()> {
         self.print_inner_attributes(attrs)?;
-        for item_id in &_mod.item_ids {
-            self.print_item_id(item_id)?;
+        for &item_id in &_mod.item_ids {
+            self.ann.nested(self, Nested::Item(item_id))?;
         }
         Ok(())
     }
@@ -545,16 +428,16 @@ impl<'a> State<'a> {
             hir::TyImplTrait(ref bounds) => {
                 self.print_bounds("impl ", &bounds[..])?;
             }
-            hir::TyArray(ref ty, ref v) => {
+            hir::TyArray(ref ty, v) => {
                 word(&mut self.s, "[")?;
                 self.print_type(&ty)?;
                 word(&mut self.s, "; ")?;
-                self.print_expr(&v)?;
+                self.ann.nested(self, Nested::Body(v))?;
                 word(&mut self.s, "]")?;
             }
-            hir::TyTypeof(ref e) => {
+            hir::TyTypeof(e) => {
                 word(&mut self.s, "typeof(")?;
-                self.print_expr(&e)?;
+                self.ann.nested(self, Nested::Body(e))?;
                 word(&mut self.s, ")")?;
             }
             hir::TyInfer => {
@@ -569,7 +452,7 @@ impl<'a> State<'a> {
         self.maybe_print_comment(item.span.lo)?;
         self.print_outer_attributes(&item.attrs)?;
         match item.node {
-            hir::ForeignItemFn(ref decl, ref generics) => {
+            hir::ForeignItemFn(ref decl, ref arg_names, ref generics) => {
                 self.head("")?;
                 self.print_fn(decl,
                               hir::Unsafety::Normal,
@@ -577,7 +460,9 @@ impl<'a> State<'a> {
                               Abi::Rust,
                               Some(item.name),
                               generics,
-                              &item.vis)?;
+                              &item.vis,
+                              arg_names,
+                              None)?;
                 self.end()?; // end head-ibox
                 word(&mut self.s, ";")?;
                 self.end() // end the outer fn box
@@ -600,7 +485,7 @@ impl<'a> State<'a> {
     fn print_associated_const(&mut self,
                               name: ast::Name,
                               ty: &hir::Ty,
-                              default: Option<&hir::Expr>,
+                              default: Option<hir::BodyId>,
                               vis: &hir::Visibility)
                               -> io::Result<()> {
         word(&mut self.s, &visibility_qualified(vis, ""))?;
@@ -611,7 +496,7 @@ impl<'a> State<'a> {
         if let Some(expr) = default {
             space(&mut self.s)?;
             self.word_space("=")?;
-            self.print_expr(expr)?;
+            self.ann.nested(self, Nested::Body(expr))?;
         }
         word(&mut self.s, ";")
     }
@@ -634,25 +519,6 @@ impl<'a> State<'a> {
         word(&mut self.s, ";")
     }
 
-    pub fn print_item_id(&mut self, item_id: &hir::ItemId) -> io::Result<()> {
-        if let Some(krate) = self.krate {
-            // skip nested items if krate context was not provided
-            let item = &krate.items[&item_id.id];
-            self.print_item(item)
-        } else {
-            Ok(())
-        }
-    }
-
-    pub fn print_expr_id(&mut self, expr_id: &hir::ExprId) -> io::Result<()> {
-        if let Some(krate) = self.krate {
-            let expr = &krate.exprs[expr_id];
-            self.print_expr(expr)
-        } else {
-            Ok(())
-        }
-    }
-
     /// Pretty-print an item
     pub fn print_item(&mut self, item: &hir::Item) -> io::Result<()> {
         self.hardbreak_if_not_bol()?;
@@ -697,7 +563,7 @@ impl<'a> State<'a> {
                 self.end()?; // end inner head-block
                 self.end()?; // end outer head-block
             }
-            hir::ItemStatic(ref ty, m, ref expr) => {
+            hir::ItemStatic(ref ty, m, expr) => {
                 self.head(&visibility_qualified(&item.vis, "static"))?;
                 if m == hir::MutMutable {
                     self.word_space("mut")?;
@@ -709,11 +575,11 @@ impl<'a> State<'a> {
                 self.end()?; // end the head-ibox
 
                 self.word_space("=")?;
-                self.print_expr(&expr)?;
+                self.ann.nested(self, Nested::Body(expr))?;
                 word(&mut self.s, ";")?;
                 self.end()?; // end the outer cbox
             }
-            hir::ItemConst(ref ty, ref expr) => {
+            hir::ItemConst(ref ty, expr) => {
                 self.head(&visibility_qualified(&item.vis, "const"))?;
                 self.print_name(item.name)?;
                 self.word_space(":")?;
@@ -722,11 +588,11 @@ impl<'a> State<'a> {
                 self.end()?; // end the head-ibox
 
                 self.word_space("=")?;
-                self.print_expr(&expr)?;
+                self.ann.nested(self, Nested::Body(expr))?;
                 word(&mut self.s, ";")?;
                 self.end()?; // end the outer cbox
             }
-            hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, ref body) => {
+            hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, body) => {
                 self.head("")?;
                 self.print_fn(decl,
                               unsafety,
@@ -734,11 +600,13 @@ impl<'a> State<'a> {
                               abi,
                               Some(item.name),
                               typarams,
-                              &item.vis)?;
+                              &item.vis,
+                              &[],
+                              Some(body))?;
                 word(&mut self.s, " ")?;
                 self.end()?; // need to close a box
                 self.end()?; // need to close a box
-                self.print_expr_id(body)?;
+                self.ann.nested(self, Nested::Body(body))?;
             }
             hir::ItemMod(ref _mod) => {
                 self.head(&visibility_qualified(&item.vis, "mod"))?;
@@ -832,7 +700,7 @@ impl<'a> State<'a> {
                 self.bopen()?;
                 self.print_inner_attributes(&item.attrs)?;
                 for impl_item in impl_items {
-                    self.print_impl_item_ref(impl_item)?;
+                    self.ann.nested(self, Nested::ImplItem(impl_item.id))?;
                 }
                 self.bclose(item.span)?;
             }
@@ -858,7 +726,7 @@ impl<'a> State<'a> {
                 word(&mut self.s, " ")?;
                 self.bopen()?;
                 for trait_item in trait_items {
-                    self.print_trait_item(trait_item)?;
+                    self.ann.nested(self, Nested::TraitItem(trait_item.id))?;
                 }
                 self.bclose(item.span)?;
             }
@@ -928,8 +796,11 @@ impl<'a> State<'a> {
         match *vis {
             hir::Public => self.word_nbsp("pub"),
             hir::Visibility::Crate => self.word_nbsp("pub(crate)"),
-            hir::Visibility::Restricted { ref path, .. } =>
-                self.word_nbsp(&format!("pub({})", path)),
+            hir::Visibility::Restricted { ref path, .. } => {
+                word(&mut self.s, "pub(")?;
+                self.print_path(path, false)?;
+                self.word_nbsp(")")
+            }
             hir::Inherited => Ok(()),
         }
     }
@@ -985,19 +856,19 @@ impl<'a> State<'a> {
         self.head("")?;
         let generics = hir::Generics::empty();
         self.print_struct(&v.node.data, &generics, v.node.name, v.span, false)?;
-        match v.node.disr_expr {
-            Some(ref d) => {
-                space(&mut self.s)?;
-                self.word_space("=")?;
-                self.print_expr(&d)
-            }
-            _ => Ok(()),
+        if let Some(d) = v.node.disr_expr {
+            space(&mut self.s)?;
+            self.word_space("=")?;
+            self.ann.nested(self, Nested::Body(d))?;
         }
+        Ok(())
     }
     pub fn print_method_sig(&mut self,
                             name: ast::Name,
                             m: &hir::MethodSig,
-                            vis: &hir::Visibility)
+                            vis: &hir::Visibility,
+                            arg_names: &[Spanned<ast::Name>],
+                            body_id: Option<hir::BodyId>)
                             -> io::Result<()> {
         self.print_fn(&m.decl,
                       m.unsafety,
@@ -1005,7 +876,9 @@ impl<'a> State<'a> {
                       m.abi,
                       Some(name),
                       &m.generics,
-                      vis)
+                      vis,
+                      arg_names,
+                      body_id)
     }
 
     pub fn print_trait_item(&mut self, ti: &hir::TraitItem) -> io::Result<()> {
@@ -1014,27 +887,22 @@ impl<'a> State<'a> {
         self.maybe_print_comment(ti.span.lo)?;
         self.print_outer_attributes(&ti.attrs)?;
         match ti.node {
-            hir::ConstTraitItem(ref ty, ref default) => {
-                self.print_associated_const(ti.name,
-                                            &ty,
-                                            default.as_ref().map(|expr| &**expr),
-                                            &hir::Inherited)?;
-            }
-            hir::MethodTraitItem(ref sig, ref body) => {
-                if body.is_some() {
-                    self.head("")?;
-                }
-                self.print_method_sig(ti.name, sig, &hir::Inherited)?;
-                if let Some(ref body) = *body {
-                    self.nbsp()?;
-                    self.end()?; // need to close a box
-                    self.end()?; // need to close a box
-                    self.print_expr_id(body)?;
-                } else {
-                    word(&mut self.s, ";")?;
-                }
+            hir::TraitItemKind::Const(ref ty, default) => {
+                self.print_associated_const(ti.name, &ty, default, &hir::Inherited)?;
             }
-            hir::TypeTraitItem(ref bounds, ref default) => {
+            hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref arg_names)) => {
+                self.print_method_sig(ti.name, sig, &hir::Inherited, arg_names, None)?;
+                word(&mut self.s, ";")?;
+            }
+            hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
+                self.head("")?;
+                self.print_method_sig(ti.name, sig, &hir::Inherited, &[], Some(body))?;
+                self.nbsp()?;
+                self.end()?; // need to close a box
+                self.end()?; // need to close a box
+                self.ann.nested(self, Nested::Body(body))?;
+            }
+            hir::TraitItemKind::Type(ref bounds, ref default) => {
                 self.print_associated_type(ti.name,
                                            Some(bounds),
                                            default.as_ref().map(|ty| &**ty))?;
@@ -1043,16 +911,6 @@ impl<'a> State<'a> {
         self.ann.post(self, NodeSubItem(ti.id))
     }
 
-    pub fn print_impl_item_ref(&mut self, item_ref: &hir::ImplItemRef) -> io::Result<()> {
-        if let Some(krate) = self.krate {
-            // skip nested items if krate context was not provided
-            let item = &krate.impl_item(item_ref.id);
-            self.print_impl_item(item)
-        } else {
-            Ok(())
-        }
-    }
-
     pub fn print_impl_item(&mut self, ii: &hir::ImplItem) -> io::Result<()> {
         self.ann.pre(self, NodeSubItem(ii.id))?;
         self.hardbreak_if_not_bol()?;
@@ -1065,16 +923,16 @@ impl<'a> State<'a> {
         }
 
         match ii.node {
-            hir::ImplItemKind::Const(ref ty, ref expr) => {
-                self.print_associated_const(ii.name, &ty, Some(&expr), &ii.vis)?;
+            hir::ImplItemKind::Const(ref ty, expr) => {
+                self.print_associated_const(ii.name, &ty, Some(expr), &ii.vis)?;
             }
-            hir::ImplItemKind::Method(ref sig, ref body) => {
+            hir::ImplItemKind::Method(ref sig, body) => {
                 self.head("")?;
-                self.print_method_sig(ii.name, sig, &ii.vis)?;
+                self.print_method_sig(ii.name, sig, &ii.vis, &[], Some(body))?;
                 self.nbsp()?;
                 self.end()?; // need to close a box
                 self.end()?; // need to close a box
-                self.print_expr_id(body)?;
+                self.ann.nested(self, Nested::Body(body))?;
             }
             hir::ImplItemKind::Type(ref ty) => {
                 self.print_associated_type(ii.name, None, Some(ty))?;
@@ -1246,12 +1104,12 @@ impl<'a> State<'a> {
         self.end()
     }
 
-    fn print_expr_repeat(&mut self, element: &hir::Expr, count: &hir::Expr) -> io::Result<()> {
+    fn print_expr_repeat(&mut self, element: &hir::Expr, count: hir::BodyId) -> io::Result<()> {
         self.ibox(indent_unit)?;
         word(&mut self.s, "[")?;
         self.print_expr(element)?;
         self.word_space(";")?;
-        self.print_expr(count)?;
+        self.ann.nested(self, Nested::Body(count))?;
         word(&mut self.s, "]")?;
         self.end()
     }
@@ -1362,8 +1220,8 @@ impl<'a> State<'a> {
             hir::ExprArray(ref exprs) => {
                 self.print_expr_vec(exprs)?;
             }
-            hir::ExprRepeat(ref element, ref count) => {
-                self.print_expr_repeat(&element, &count)?;
+            hir::ExprRepeat(ref element, count) => {
+                self.print_expr_repeat(&element, count)?;
             }
             hir::ExprStruct(ref qpath, ref fields, ref wth) => {
                 self.print_expr_struct(qpath, &fields[..], wth)?;
@@ -1434,14 +1292,14 @@ impl<'a> State<'a> {
                 }
                 self.bclose_(expr.span, indent_unit)?;
             }
-            hir::ExprClosure(capture_clause, ref decl, ref body, _fn_decl_span) => {
+            hir::ExprClosure(capture_clause, ref decl, body, _fn_decl_span) => {
                 self.print_capture_clause(capture_clause)?;
 
-                self.print_fn_block_args(&decl)?;
+                self.print_closure_args(&decl, body)?;
                 space(&mut self.s)?;
 
                 // this is a bare expression
-                self.print_expr_id(body)?;
+                self.ann.nested(self, Nested::Body(body))?;
                 self.end()?; // need to close a box
 
                 // a box will be closed by print_expr, but we didn't want an overall
@@ -1615,8 +1473,8 @@ impl<'a> State<'a> {
                 }
                 self.end()
             }
-            hir::DeclItem(ref item) => {
-                self.print_item_id(item)
+            hir::DeclItem(item) => {
+                self.ann.nested(self, Nested::Item(item))
             }
         }
     }
@@ -1637,10 +1495,10 @@ impl<'a> State<'a> {
         self.print_expr(coll)
     }
 
-    fn print_path(&mut self,
-                  path: &hir::Path,
-                  colons_before_params: bool)
-                  -> io::Result<()> {
+    pub fn print_path(&mut self,
+                      path: &hir::Path,
+                      colons_before_params: bool)
+                      -> io::Result<()> {
         self.maybe_print_comment(path.span.lo)?;
 
         for (i, segment) in path.segments.iter().enumerate() {
@@ -1656,10 +1514,10 @@ impl<'a> State<'a> {
         Ok(())
     }
 
-    fn print_qpath(&mut self,
-                   qpath: &hir::QPath,
-                   colons_before_params: bool)
-                   -> io::Result<()> {
+    pub fn print_qpath(&mut self,
+                       qpath: &hir::QPath,
+                       colons_before_params: bool)
+                       -> io::Result<()> {
         match *qpath {
             hir::QPath::Resolved(None, ref path) => {
                 self.print_path(path, colons_before_params)
@@ -1954,27 +1812,6 @@ impl<'a> State<'a> {
         self.end() // close enclosing cbox
     }
 
-    fn print_explicit_self(&mut self, explicit_self: &hir::ExplicitSelf) -> io::Result<()> {
-        match explicit_self.node {
-            SelfKind::Value(m) => {
-                self.print_mutability(m)?;
-                word(&mut self.s, "self")
-            }
-            SelfKind::Region(ref lt, m) => {
-                word(&mut self.s, "&")?;
-                self.print_opt_lifetime(lt)?;
-                self.print_mutability(m)?;
-                word(&mut self.s, "self")
-            }
-            SelfKind::Explicit(ref typ, m) => {
-                self.print_mutability(m)?;
-                word(&mut self.s, "self")?;
-                self.word_space(":")?;
-                self.print_type(&typ)
-            }
-        }
-    }
-
     pub fn print_fn(&mut self,
                     decl: &hir::FnDecl,
                     unsafety: hir::Unsafety,
@@ -1982,7 +1819,9 @@ impl<'a> State<'a> {
                     abi: Abi,
                     name: Option<ast::Name>,
                     generics: &hir::Generics,
-                    vis: &hir::Visibility)
+                    vis: &hir::Visibility,
+                    arg_names: &[Spanned<ast::Name>],
+                    body_id: Option<hir::BodyId>)
                     -> io::Result<()> {
         self.print_fn_header_info(unsafety, constness, abi, vis)?;
 
@@ -1991,24 +1830,51 @@ impl<'a> State<'a> {
             self.print_name(name)?;
         }
         self.print_generics(generics)?;
-        self.print_fn_args_and_ret(decl)?;
-        self.print_where_clause(&generics.where_clause)
-    }
 
-    pub fn print_fn_args_and_ret(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
         self.popen()?;
-        self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, false))?;
+        let mut i = 0;
+        // Make sure we aren't supplied *both* `arg_names` and `body_id`.
+        assert!(arg_names.is_empty() || body_id.is_none());
+        self.commasep(Inconsistent, &decl.inputs, |s, ty| {
+            s.ibox(indent_unit)?;
+            if let Some(name) = arg_names.get(i) {
+                word(&mut s.s, &name.node.as_str())?;
+                word(&mut s.s, ":")?;
+                space(&mut s.s)?;
+            } else if let Some(body_id) = body_id {
+                s.ann.nested(s, Nested::BodyArgPat(body_id, i))?;
+                word(&mut s.s, ":")?;
+                space(&mut s.s)?;
+            }
+            i += 1;
+            s.print_type(ty)?;
+            s.end()
+        })?;
         if decl.variadic {
             word(&mut self.s, ", ...")?;
         }
         self.pclose()?;
 
-        self.print_fn_output(decl)
+        self.print_fn_output(decl)?;
+        self.print_where_clause(&generics.where_clause)
     }
 
-    pub fn print_fn_block_args(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
+    fn print_closure_args(&mut self, decl: &hir::FnDecl, body_id: hir::BodyId) -> io::Result<()> {
         word(&mut self.s, "|")?;
-        self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, true))?;
+        let mut i = 0;
+        self.commasep(Inconsistent, &decl.inputs, |s, ty| {
+            s.ibox(indent_unit)?;
+
+            s.ann.nested(s, Nested::BodyArgPat(body_id, i))?;
+            i += 1;
+
+            if ty.node != hir::TyInfer {
+                word(&mut s.s, ":")?;
+                space(&mut s.s)?;
+                s.print_type(ty)?;
+            }
+            s.end()
+        })?;
         word(&mut self.s, "|")?;
 
         if let hir::DefaultReturn(..) = decl.output {
@@ -2180,31 +2046,6 @@ impl<'a> State<'a> {
         self.print_type(&mt.ty)
     }
 
-    pub fn print_arg(&mut self, input: &hir::Arg, is_closure: bool) -> io::Result<()> {
-        self.ibox(indent_unit)?;
-        match input.ty.node {
-            hir::TyInfer if is_closure => self.print_pat(&input.pat)?,
-            _ => {
-                if let Some(eself) = input.to_self() {
-                    self.print_explicit_self(&eself)?;
-                } else {
-                    let invalid = if let PatKind::Binding(_, _, name, _) = input.pat.node {
-                        name.node == keywords::Invalid.name()
-                    } else {
-                        false
-                    };
-                    if !invalid {
-                        self.print_pat(&input.pat)?;
-                        word(&mut self.s, ":")?;
-                        space(&mut self.s)?;
-                    }
-                    self.print_type(&input.ty)?;
-                }
-            }
-        }
-        self.end()
-    }
-
     pub fn print_fn_output(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
         if let hir::DefaultReturn(..) = decl.output {
             return Ok(());
@@ -2252,7 +2093,9 @@ impl<'a> State<'a> {
                       abi,
                       name,
                       &generics,
-                      &hir::Inherited)?;
+                      &hir::Inherited,
+                      &[],
+                      None)?;
         self.end()
     }
 
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 9d48fbca53edd..9ff7dcc7d5883 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -75,7 +75,6 @@ use std::collections::HashSet;
 
 use hir::map as ast_map;
 use hir;
-use hir::print as pprust;
 
 use lint;
 use hir::def::Def;
@@ -1051,8 +1050,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             Some(ref node) => match *node {
                 ast_map::NodeItem(ref item) => {
                     match item.node {
-                        hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, _) => {
-                            Some((fn_decl, gen, unsafety, constness, item.name, item.span))
+                        hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, body) => {
+                            Some((fn_decl, gen, unsafety, constness, item.name, item.span, body))
                         }
                         _ => None,
                     }
@@ -1066,26 +1065,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             return;
                         }
                     }
-                    if let hir::ImplItemKind::Method(ref sig, _) = item.node {
+                    if let hir::ImplItemKind::Method(ref sig, body) = item.node {
                         Some((&sig.decl,
                               &sig.generics,
                               sig.unsafety,
                               sig.constness,
                               item.name,
-                              item.span))
+                              item.span,
+                              body))
                     } else {
                         None
                     }
                 },
                 ast_map::NodeTraitItem(item) => {
                     match item.node {
-                        hir::MethodTraitItem(ref sig, Some(_)) => {
+                        hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
                             Some((&sig.decl,
                                   &sig.generics,
                                   sig.unsafety,
                                   sig.constness,
                                   item.name,
-                                  item.span))
+                                  item.span,
+                                  body))
                         }
                         _ => None,
                     }
@@ -1094,12 +1095,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             },
             None => None,
         };
-        let (fn_decl, generics, unsafety, constness, name, span)
+        let (fn_decl, generics, unsafety, constness, name, span, body)
                                     = node_inner.expect("expect item fn");
         let rebuilder = Rebuilder::new(self.tcx, fn_decl, generics, same_regions, &life_giver);
         let (fn_decl, generics) = rebuilder.rebuild();
         self.give_expl_lifetime_param(
-            err, &fn_decl, unsafety, constness, name, &generics, span);
+            err, &fn_decl, unsafety, constness, name, &generics, span, body);
     }
 
     pub fn issue_32330_warnings(&self, span: Span, issue32330s: &[ty::Issue32330]) {
@@ -1375,23 +1376,14 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
     }
 
     fn rebuild_args_ty(&self,
-                       inputs: &[hir::Arg],
+                       inputs: &[P<hir::Ty>],
                        lifetime: hir::Lifetime,
                        anon_nums: &HashSet<u32>,
                        region_names: &HashSet<ast::Name>)
-                       -> hir::HirVec<hir::Arg> {
-        let mut new_inputs = Vec::new();
-        for arg in inputs {
-            let new_ty = self.rebuild_arg_ty_or_output(&arg.ty, lifetime,
-                                                       anon_nums, region_names);
-            let possibly_new_arg = hir::Arg {
-                ty: new_ty,
-                pat: arg.pat.clone(),
-                id: arg.id
-            };
-            new_inputs.push(possibly_new_arg);
-        }
-        new_inputs.into()
+                       -> hir::HirVec<P<hir::Ty>> {
+        inputs.iter().map(|arg_ty| {
+            self.rebuild_arg_ty_or_output(arg_ty, lifetime, anon_nums, region_names)
+        }).collect()
     }
 
     fn rebuild_output(&self, ty: &hir::FunctionRetTy,
@@ -1634,10 +1626,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                 constness: hir::Constness,
                                 name: ast::Name,
                                 generics: &hir::Generics,
-                                span: Span) {
-        let suggested_fn = pprust::fun_to_string(decl, unsafety, constness, name, generics);
-        let msg = format!("consider using an explicit lifetime \
-                           parameter as shown: {}", suggested_fn);
+                                span: Span,
+                                body: hir::BodyId) {
+        let s = hir::print::to_string(&self.tcx.map, |s| {
+            use syntax::abi::Abi;
+            use syntax::print::pprust::PrintState;
+
+            s.head("")?;
+            s.print_fn(decl,
+                       unsafety,
+                       constness,
+                       Abi::Rust,
+                       Some(name),
+                       generics,
+                       &hir::Inherited,
+                       &[],
+                       Some(body))?;
+            s.end()?; // Close the head box
+            s.end()   // Close the outer box
+        });
+        let msg = format!("consider using an explicit lifetime parameter as shown: {}", s);
         err.span_help(span, &msg[..]);
     }
 
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 17cc34fcd8394..ff508d2d8194a 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -33,6 +33,7 @@
 #![cfg_attr(stage0, feature(item_like_imports))]
 #![feature(libc)]
 #![feature(nonzero)]
+#![feature(pub_restricted)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
@@ -80,9 +81,8 @@ pub mod lint;
 
 pub mod middle {
     pub mod astconv_util;
-    pub mod expr_use_visitor; // STAGE0: increase glitch immunity
+    pub mod expr_use_visitor;
     pub mod const_val;
-    pub mod const_qualif;
     pub mod cstore;
     pub mod dataflow;
     pub mod dead;
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 3ff2abac277b5..cce79820ca8da 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -821,6 +821,7 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
         self.with_lint_attrs(&e.attrs, |cx| {
             run_lints!(cx, check_expr, late_passes, e);
             hir_visit::walk_expr(cx, e);
+            run_lints!(cx, check_expr_post, late_passes, e);
         })
     }
 
@@ -835,8 +836,8 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,
-                body_id: hir::ExprId, span: Span, id: ast::NodeId) {
-        let body = self.tcx.map.expr(body_id);
+                body_id: hir::BodyId, span: Span, id: ast::NodeId) {
+        let body = self.tcx.map.body(body_id);
         run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
         hir_visit::walk_fn(self, fk, decl, body_id, span, id);
         run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id);
@@ -909,10 +910,6 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
         hir_visit::walk_decl(self, d);
     }
 
-    fn visit_expr_post(&mut self, e: &'tcx hir::Expr) {
-        run_lints!(self, check_expr_post, late_passes, e);
-    }
-
     fn visit_generics(&mut self, g: &'tcx hir::Generics) {
         run_lints!(self, check_generics, late_passes, g);
         hir_visit::walk_generics(self, g);
diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs
index ccf53f01cd532..7e0da00694c4a 100644
--- a/src/librustc/lint/mod.rs
+++ b/src/librustc/lint/mod.rs
@@ -162,14 +162,14 @@ pub trait LateLintPass<'a, 'tcx>: LintPass {
                 _: &LateContext<'a, 'tcx>,
                 _: FnKind<'tcx>,
                 _: &'tcx hir::FnDecl,
-                _: &'tcx hir::Expr,
+                _: &'tcx hir::Body,
                 _: Span,
                 _: ast::NodeId) { }
     fn check_fn_post(&mut self,
                      _: &LateContext<'a, 'tcx>,
                      _: FnKind<'tcx>,
                      _: &'tcx hir::FnDecl,
-                     _: &'tcx hir::Expr,
+                     _: &'tcx hir::Body,
                      _: Span,
                      _: ast::NodeId) { }
     fn check_trait_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::TraitItem) { }
diff --git a/src/librustc/middle/const_qualif.rs b/src/librustc/middle/const_qualif.rs
deleted file mode 100644
index ec98637922ee3..0000000000000
--- a/src/librustc/middle/const_qualif.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Const qualification, from partial to completely promotable.
-bitflags! {
-    #[derive(RustcEncodable, RustcDecodable)]
-    flags ConstQualif: u8 {
-        // Inner mutability (can not be placed behind a reference) or behind
-        // &mut in a non-global expression. Can be copied from static memory.
-        const MUTABLE_MEM        = 1 << 0,
-        // Constant value with a type that implements Drop. Can be copied
-        // from static memory, similar to MUTABLE_MEM.
-        const NEEDS_DROP         = 1 << 1,
-        // Even if the value can be placed in static memory, copying it from
-        // there is more expensive than in-place instantiation, and/or it may
-        // be too large. This applies to [T; N] and everything containing it.
-        // N.B.: references need to clear this flag to not end up on the stack.
-        const PREFER_IN_PLACE    = 1 << 2,
-        // May use more than 0 bytes of memory, doesn't impact the constness
-        // directly, but is not allowed to be borrowed mutably in a constant.
-        const NON_ZERO_SIZED     = 1 << 3,
-        // Actually borrowed, has to always be in static memory. Does not
-        // propagate, and requires the expression to behave like a 'static
-        // lvalue. The set of expressions with this flag is the minimum
-        // that have to be promoted.
-        const HAS_STATIC_BORROWS = 1 << 4,
-        // Invalid const for miscellaneous reasons (e.g. not implemented).
-        const NOT_CONST          = 1 << 5,
-
-        // Borrowing the expression won't produce &'static T if any of these
-        // bits are set, though the value could be copied from static memory
-        // if `NOT_CONST` isn't set.
-        const NON_STATIC_BORROWS = ConstQualif::MUTABLE_MEM.bits |
-                                   ConstQualif::NEEDS_DROP.bits |
-                                   ConstQualif::NOT_CONST.bits
-    }
-}
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index d0003693eefe3..7151e5226cab0 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -33,17 +33,17 @@ use mir::Mir;
 use session::Session;
 use session::search_paths::PathKind;
 use util::nodemap::{NodeSet, DefIdMap};
+
+use std::collections::BTreeMap;
 use std::path::PathBuf;
 use std::rc::Rc;
 use syntax::ast;
 use syntax::attr;
 use syntax::ext::base::SyntaxExtension;
-use syntax::ptr::P;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
 use rustc_back::target::Target;
 use hir;
-use hir::intravisit::Visitor;
 use rustc_back::PanicStrategy;
 
 pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown};
@@ -134,102 +134,6 @@ pub struct NativeLibrary {
     pub foreign_items: Vec<DefIndex>,
 }
 
-/// The data we save and restore about an inlined item or method.  This is not
-/// part of the AST that we parse from a file, but it becomes part of the tree
-/// that we trans.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct InlinedItem {
-    pub def_id: DefId,
-    pub body: P<hir::Expr>,
-    pub const_fn_args: Vec<Option<DefId>>,
-}
-
-/// A borrowed version of `hir::InlinedItem`. This is what's encoded when saving
-/// a crate; it then gets read as an InlinedItem.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, Hash, Debug)]
-pub struct InlinedItemRef<'a> {
-    pub def_id: DefId,
-    pub body: &'a hir::Expr,
-    pub const_fn_args: Vec<Option<DefId>>,
-}
-
-fn get_fn_args(decl: &hir::FnDecl) -> Vec<Option<DefId>> {
-    decl.inputs.iter().map(|arg| match arg.pat.node {
-        hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
-        _ => None
-    }).collect()
-}
-
-impl<'a> InlinedItemRef<'a> {
-    pub fn from_item<'b, 'tcx>(def_id: DefId,
-                               item: &'a hir::Item,
-                               tcx: TyCtxt<'b, 'a, 'tcx>)
-                               -> InlinedItemRef<'a> {
-        let (body, args) = match item.node {
-            hir::ItemFn(ref decl, _, _, _, _, body_id) =>
-                (tcx.map.expr(body_id), get_fn_args(decl)),
-            hir::ItemConst(_, ref body) => (&**body, Vec::new()),
-            _ => bug!("InlinedItemRef::from_item wrong kind")
-        };
-        InlinedItemRef {
-            def_id: def_id,
-            body: body,
-            const_fn_args: args
-        }
-    }
-
-    pub fn from_trait_item(def_id: DefId,
-                           item: &'a hir::TraitItem,
-                           _tcx: TyCtxt)
-                           -> InlinedItemRef<'a> {
-        let (body, args) = match item.node {
-            hir::ConstTraitItem(_, Some(ref body)) =>
-                (&**body, Vec::new()),
-            hir::ConstTraitItem(_, None) => {
-                bug!("InlinedItemRef::from_trait_item called for const without body")
-            },
-            _ => bug!("InlinedItemRef::from_trait_item wrong kind")
-        };
-        InlinedItemRef {
-            def_id: def_id,
-            body: body,
-            const_fn_args: args
-        }
-    }
-
-    pub fn from_impl_item<'b, 'tcx>(def_id: DefId,
-                                    item: &'a hir::ImplItem,
-                                    tcx: TyCtxt<'b, 'a, 'tcx>)
-                                    -> InlinedItemRef<'a> {
-        let (body, args) = match item.node {
-            hir::ImplItemKind::Method(ref sig, body_id) =>
-                (tcx.map.expr(body_id), get_fn_args(&sig.decl)),
-            hir::ImplItemKind::Const(_, ref body) =>
-                (&**body, Vec::new()),
-            _ => bug!("InlinedItemRef::from_impl_item wrong kind")
-        };
-        InlinedItemRef {
-            def_id: def_id,
-            body: body,
-            const_fn_args: args
-        }
-    }
-
-    pub fn visit<V>(&self, visitor: &mut V)
-        where V: Visitor<'a>
-    {
-        visitor.visit_expr(&self.body);
-    }
-}
-
-impl InlinedItem {
-    pub fn visit<'ast,V>(&'ast self, visitor: &mut V)
-        where V: Visitor<'ast>
-    {
-        visitor.visit_expr(&self.body);
-    }
-}
-
 pub enum LoadedMacro {
     MacroRules(ast::MacroDef),
     ProcMacro(Rc<SyntaxExtension>),
@@ -346,10 +250,10 @@ pub trait CrateStore<'tcx> {
     fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro;
 
     // misc. metadata
-    fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                              -> Option<(&'tcx InlinedItem, ast::NodeId)>;
-    fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId>;
-    fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId>;
+    fn maybe_get_item_body<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                               -> Option<&'tcx hir::Body>;
+    fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body>;
+    fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool;
 
     fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx>;
     fn is_item_mir_available(&self, def: DefId) -> bool;
@@ -516,15 +420,15 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
     fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") }
 
     // misc. metadata
-    fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                              -> Option<(&'tcx InlinedItem, ast::NodeId)> {
-        bug!("maybe_get_item_ast")
+    fn maybe_get_item_body<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                               -> Option<&'tcx hir::Body> {
+        bug!("maybe_get_item_body")
     }
-    fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId> {
-        bug!("local_node_for_inlined_defid")
+    fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
+        bug!("item_body_nested_bodies")
     }
-    fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId> {
-        bug!("defid_for_inlined_node")
+    fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool {
+        bug!("const_is_rvalue_promotable_to_static")
     }
 
     fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index f7a34c43cccbd..dfcb5cb7b79fe 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -108,6 +108,9 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
 }
 
 impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O> {
+    fn nested(&self, state: &mut pprust::State, nested: pprust::Nested) -> io::Result<()> {
+        pprust::PpAnn::nested(&self.tcx.map, state, nested)
+    }
     fn pre(&self,
            ps: &mut pprust::State,
            node: pprust::AnnNode) -> io::Result<()> {
@@ -160,7 +163,7 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O
     }
 }
 
-fn build_nodeid_to_index(decl: Option<&hir::FnDecl>,
+fn build_nodeid_to_index(body: Option<&hir::Body>,
                          cfg: &cfg::CFG) -> NodeMap<Vec<CFGIndex>> {
     let mut index = NodeMap();
 
@@ -168,8 +171,8 @@ fn build_nodeid_to_index(decl: Option<&hir::FnDecl>,
     // into cfg itself?  i.e. introduce a fn-based flow-graph in
     // addition to the current block-based flow-graph, rather than
     // have to put traversals like this here?
-    if let Some(decl) = decl {
-        add_entries_from_fn_decl(&mut index, decl, cfg.entry);
+    if let Some(body) = body {
+        add_entries_from_fn_body(&mut index, body, cfg.entry);
     }
 
     cfg.graph.each_node(|node_idx, node| {
@@ -181,20 +184,24 @@ fn build_nodeid_to_index(decl: Option<&hir::FnDecl>,
 
     return index;
 
-    fn add_entries_from_fn_decl(index: &mut NodeMap<Vec<CFGIndex>>,
-                                decl: &hir::FnDecl,
+    /// Add mappings from the ast nodes for the formal bindings to
+    /// the entry-node in the graph.
+    fn add_entries_from_fn_body(index: &mut NodeMap<Vec<CFGIndex>>,
+                                body: &hir::Body,
                                 entry: CFGIndex) {
-        //! add mappings from the ast nodes for the formal bindings to
-        //! the entry-node in the graph.
+        use hir::intravisit::Visitor;
+
         struct Formals<'a> {
             entry: CFGIndex,
             index: &'a mut NodeMap<Vec<CFGIndex>>,
         }
         let mut formals = Formals { entry: entry, index: index };
-        intravisit::walk_fn_decl(&mut formals, decl);
-        impl<'a, 'v> intravisit::Visitor<'v> for Formals<'a> {
+        for arg in &body.arguments {
+            formals.visit_pat(&arg.pat);
+        }
+        impl<'a, 'v> Visitor<'v> for Formals<'a> {
             fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'v> {
-                panic!("should not encounter fn bodies or items")
+                intravisit::NestedVisitorMap::None
             }
 
             fn visit_pat(&mut self, p: &hir::Pat) {
@@ -227,7 +234,7 @@ pub enum KillFrom {
 impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
     pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                analysis_name: &'static str,
-               decl: Option<&hir::FnDecl>,
+               body: Option<&hir::Body>,
                cfg: &cfg::CFG,
                oper: O,
                id_range: IdRange,
@@ -250,7 +257,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
         let kills2 = zeroes;
         let on_entry = vec![entry; num_nodes * words_per_id];
 
-        let nodeid_to_index = build_nodeid_to_index(decl, cfg);
+        let nodeid_to_index = build_nodeid_to_index(body, cfg);
 
         DataFlowContext {
             tcx: tcx,
@@ -502,7 +509,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
 
 impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
 //                                ^^^^^^^^^^^^^ only needed for pretty printing
-    pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Expr) {
+    pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Body) {
         //! Performs the data flow analysis.
 
         if self.bits_per_id == 0 {
@@ -526,20 +533,11 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
         }
 
         debug!("Dataflow result for {}:", self.analysis_name);
-        debug!("{}", {
-            let mut v = Vec::new();
-            self.pretty_print_to(box &mut v, body).unwrap();
-            String::from_utf8(v).unwrap()
-        });
-    }
-
-    fn pretty_print_to<'b>(&self, wr: Box<io::Write + 'b>,
-                           body: &hir::Expr) -> io::Result<()> {
-        let mut ps = pprust::rust_printer_annotated(wr, self, None);
-        ps.cbox(pprust::indent_unit)?;
-        ps.ibox(0)?;
-        ps.print_expr(body)?;
-        pp::eof(&mut ps.s)
+        debug!("{}", pprust::to_string(self, |s| {
+            s.cbox(pprust::indent_unit)?;
+            s.ibox(0)?;
+            s.print_expr(&body.value)
+        }));
     }
 }
 
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 1c5dd97b74bd3..76adee4e00c15 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -328,11 +328,12 @@ impl<'v, 'k> ItemLikeVisitor<'v> for LifeSeeder<'k> {
                 self.worklist.extend(enum_def.variants.iter()
                                                       .map(|variant| variant.node.data.id()));
             }
-            hir::ItemTrait(.., ref trait_items) => {
-                for trait_item in trait_items {
+            hir::ItemTrait(.., ref trait_item_refs) => {
+                for trait_item_ref in trait_item_refs {
+                    let trait_item = self.krate.trait_item(trait_item_ref.id);
                     match trait_item.node {
-                        hir::ConstTraitItem(_, Some(_)) |
-                        hir::MethodTraitItem(_, Some(_)) => {
+                        hir::TraitItemKind::Const(_, Some(_)) |
+                        hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
                             if has_allow_dead_code_or_lang_attr(&trait_item.attrs) {
                                 self.worklist.push(trait_item.id);
                             }
@@ -354,6 +355,10 @@ impl<'v, 'k> ItemLikeVisitor<'v> for LifeSeeder<'k> {
         }
     }
 
+    fn visit_trait_item(&mut self, _item: &hir::TraitItem) {
+        // ignore: we are handling this in `visit_item` above
+    }
+
     fn visit_impl_item(&mut self, _item: &hir::ImplItem) {
         // ignore: we are handling this in `visit_item` above
     }
@@ -546,19 +551,19 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
         match impl_item.node {
-            hir::ImplItemKind::Const(_, ref expr) => {
+            hir::ImplItemKind::Const(_, body_id) => {
                 if !self.symbol_is_live(impl_item.id, None) {
                     self.warn_dead_code(impl_item.id, impl_item.span,
                                         impl_item.name, "associated const");
                 }
-                intravisit::walk_expr(self, expr)
+                self.visit_nested_body(body_id)
             }
             hir::ImplItemKind::Method(_, body_id) => {
                 if !self.symbol_is_live(impl_item.id, None) {
                     self.warn_dead_code(impl_item.id, impl_item.span,
                                         impl_item.name, "method");
                 }
-                self.visit_body(body_id)
+                self.visit_nested_body(body_id)
             }
             hir::ImplItemKind::Type(..) => {}
         }
@@ -567,15 +572,13 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
     // Overwrite so that we don't warn the trait item itself.
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
         match trait_item.node {
-            hir::ConstTraitItem(_, Some(ref body)) => {
-                intravisit::walk_expr(self, body)
-            }
-            hir::MethodTraitItem(_, Some(body_id)) => {
-                self.visit_body(body_id)
+            hir::TraitItemKind::Const(_, Some(body_id)) |
+            hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)) => {
+                self.visit_nested_body(body_id)
             }
-            hir::ConstTraitItem(_, None) |
-            hir::MethodTraitItem(_, None) |
-            hir::TypeTraitItem(..) => {}
+            hir::TraitItemKind::Const(_, None) |
+            hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
+            hir::TraitItemKind::Type(..) => {}
         }
     }
 }
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index 2ec7aa4c4d903..38b0b18b0129a 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -98,7 +98,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, fn_decl: &'tcx hir::FnDecl,
-                body_id: hir::ExprId, span: Span, id: ast::NodeId) {
+                body_id: hir::BodyId, span: Span, id: ast::NodeId) {
 
         let (is_item_fn, is_unsafe_fn) = match fn_kind {
             FnKind::ItemFn(_, _, unsafety, ..) =>
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index e927843a984b8..f2e46d4cbc96b 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -17,7 +17,7 @@ use syntax::ast::NodeId;
 use syntax::attr;
 use syntax::entry::EntryPointType;
 use syntax_pos::Span;
-use hir::{Item, ItemFn, ImplItem};
+use hir::{Item, ItemFn, ImplItem, TraitItem};
 use hir::itemlikevisit::ItemLikeVisitor;
 
 struct EntryContext<'a, 'tcx: 'a> {
@@ -47,6 +47,9 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
         find_item(item, self, at_root);
     }
 
+    fn visit_trait_item(&mut self, _trait_item: &'tcx TraitItem) {
+        // entry fn is never a trait item
+    }
 
     fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem) {
         // entry fn is never an impl item
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index b3e61f1e57067..a3a49c916338e 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -287,20 +287,11 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn walk_fn(&mut self,
-                   decl: &hir::FnDecl,
-                   body: &hir::Expr) {
-        self.walk_arg_patterns(decl, body);
-        self.consume_expr(body);
-    }
-
-    fn walk_arg_patterns(&mut self,
-                         decl: &hir::FnDecl,
-                         body: &hir::Expr) {
-        for arg in &decl.inputs {
+    pub fn consume_body(&mut self, body: &hir::Body) {
+        for arg in &body.arguments {
             let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id));
 
-            let fn_body_scope_r = self.tcx().node_scope_region(body.id);
+            let fn_body_scope_r = self.tcx().node_scope_region(body.value.id);
             let arg_cmt = self.mc.cat_rvalue(
                 arg.id,
                 arg.pat.span,
@@ -309,6 +300,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
 
             self.walk_irrefutable_pat(arg_cmt, &arg.pat);
         }
+
+        self.consume_expr(&body.value);
     }
 
     fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
@@ -537,9 +530,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                 }
             }
 
-            hir::ExprRepeat(ref base, ref count) => {
+            hir::ExprRepeat(ref base, _) => {
                 self.consume_expr(&base);
-                self.consume_expr(&count);
             }
 
             hir::ExprClosure(.., fn_decl_span) => {
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index 2357549c82e08..d932061d42d3d 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -34,13 +34,13 @@ struct ItemVisitor<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx> ItemVisitor<'a, 'tcx> {
-    fn visit_const(&mut self, item_id: ast::NodeId, expr: &'tcx hir::Expr) {
+    fn visit_const(&mut self, item_id: ast::NodeId, body: hir::BodyId) {
         let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
         self.tcx.infer_ctxt(None, Some(param_env), Reveal::All).enter(|infcx| {
             let mut visitor = ExprVisitor {
                 infcx: &infcx
             };
-            visitor.visit_expr(expr);
+            visitor.visit_nested_body(body);
         });
     }
 }
@@ -122,33 +122,33 @@ impl<'a, 'tcx> Visitor<'tcx> for ItemVisitor<'a, 'tcx> {
     }
 
     // const, static and N in [T; N].
-    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
+    fn visit_body(&mut self, body: &'tcx hir::Body) {
         self.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
             let mut visitor = ExprVisitor {
                 infcx: &infcx
             };
-            visitor.visit_expr(expr);
+            visitor.visit_body(body);
         });
     }
 
     fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
-        if let hir::ConstTraitItem(_, Some(ref expr)) = item.node {
-            self.visit_const(item.id, expr);
+        if let hir::TraitItemKind::Const(_, Some(body)) = item.node {
+            self.visit_const(item.id, body);
         } else {
             intravisit::walk_trait_item(self, item);
         }
     }
 
     fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
-        if let hir::ImplItemKind::Const(_, ref expr) = item.node {
-            self.visit_const(item.id, expr);
+        if let hir::ImplItemKind::Const(_, body) = item.node {
+            self.visit_const(item.id, body);
         } else {
             intravisit::walk_impl_item(self, item);
         }
     }
 
     fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
-                b: hir::ExprId, s: Span, id: ast::NodeId) {
+                b: hir::BodyId, s: Span, id: ast::NodeId) {
         if let FnKind::Closure(..) = fk {
             span_bug!(s, "intrinsicck: closure outside of function")
         }
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 029a1d66add0b..4cae5b370eb7e 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -140,6 +140,10 @@ impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'a, 'tcx> {
         }
     }
 
+    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+        // at present, lang items are always items, not trait items
+    }
+
     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
         // at present, lang items are always items, not impl items
     }
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 445aed8f97d60..745a94a5ddba3 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -127,7 +127,6 @@ use syntax_pos::Span;
 
 use hir::Expr;
 use hir;
-use hir::print::{expr_to_string, block_to_string};
 use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
 
 /// For use with `propagate_through_loop`.
@@ -188,7 +187,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IrMaps<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
-                b: hir::ExprId, s: Span, id: NodeId) {
+                b: hir::BodyId, s: Span, id: NodeId) {
         visit_fn(self, fk, fd, b, s, id);
     }
     fn visit_local(&mut self, l: &'tcx hir::Local) { visit_local(self, l); }
@@ -354,13 +353,9 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
 
 impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.ir.tcx.map)
+        NestedVisitorMap::None
     }
 
-    fn visit_fn(&mut self, _: FnKind<'tcx>, _: &'tcx hir::FnDecl,
-                _: hir::ExprId, _: Span, _: NodeId) {
-        // do not check contents of nested fns
-    }
     fn visit_local(&mut self, l: &'tcx hir::Local) {
         check_local(self, l);
     }
@@ -375,7 +370,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
 fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
                           fk: FnKind<'tcx>,
                           decl: &'tcx hir::FnDecl,
-                          body_id: hir::ExprId,
+                          body_id: hir::BodyId,
                           sp: Span,
                           id: ast::NodeId) {
     debug!("visit_fn");
@@ -385,7 +380,9 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
 
     debug!("creating fn_maps: {:?}", &fn_maps as *const IrMaps);
 
-    for arg in &decl.inputs {
+    let body = ir.tcx.map.body(body_id);
+
+    for arg in &body.arguments {
         arg.pat.each_binding(|_bm, arg_id, _x, path1| {
             debug!("adding argument {}", arg_id);
             let name = path1.node;
@@ -408,16 +405,14 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
         clean_exit_var: fn_maps.add_variable(CleanExit)
     };
 
-    let body = ir.tcx.map.expr(body_id);
-
     // compute liveness
     let mut lsets = Liveness::new(&mut fn_maps, specials);
-    let entry_ln = lsets.compute(body);
+    let entry_ln = lsets.compute(&body.value);
 
     // check for various error conditions
-    lsets.visit_expr(body);
+    lsets.visit_body(body);
     lsets.check_ret(id, sp, fk, entry_ln, body);
-    lsets.warn_about_unused_args(decl, entry_ln);
+    lsets.warn_about_unused_args(body, entry_ln);
 }
 
 fn visit_local<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, local: &'tcx hir::Local) {
@@ -823,7 +818,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         // effectively a return---this only occurs in `for` loops,
         // where the body is really a closure.
 
-        debug!("compute: using id for body, {}", expr_to_string(body));
+        debug!("compute: using id for body, {}", self.ir.tcx.map.node_to_pretty_string(body.id));
 
         let exit_ln = self.s.exit_ln;
         let entry_ln: LiveNode = self.with_loop_nodes(body.id, exit_ln, exit_ln, |this| {
@@ -916,7 +911,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
     fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
                               -> LiveNode {
-        debug!("propagate_through_expr: {}", expr_to_string(expr));
+        debug!("propagate_through_expr: {}", self.ir.tcx.map.node_to_pretty_string(expr.id));
 
         match expr.node {
           // Interesting cases with control flow or which gen/kill
@@ -935,14 +930,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
           hir::ExprClosure(.., blk_id, _) => {
               debug!("{} is an ExprClosure",
-                     expr_to_string(expr));
+                     self.ir.tcx.map.node_to_pretty_string(expr.id));
 
               /*
               The next-node for a break is the successor of the entire
               loop. The next-node for a continue is the top of this loop.
               */
               let node = self.live_node(expr.id, expr.span);
-              self.with_loop_nodes(blk_id.node_id(), succ, node, |this| {
+              self.with_loop_nodes(blk_id.node_id, succ, node, |this| {
 
                  // the construction of a closure itself is not important,
                  // but we have to consider the closed over variables.
@@ -1088,11 +1083,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             self.propagate_through_exprs(exprs, succ)
           }
 
-          hir::ExprRepeat(ref element, ref count) => {
-            let succ = self.propagate_through_expr(&count, succ);
-            self.propagate_through_expr(&element, succ)
-          }
-
           hir::ExprStruct(_, ref fields, ref with_expr) => {
             let succ = self.propagate_through_opt_expr(with_expr.as_ref().map(|e| &**e), succ);
             fields.iter().rev().fold(succ, |succ, field| {
@@ -1149,7 +1139,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
           hir::ExprAddrOf(_, ref e) |
           hir::ExprCast(ref e, _) |
           hir::ExprType(ref e, _) |
-          hir::ExprUnary(_, ref e) => {
+          hir::ExprUnary(_, ref e) |
+          hir::ExprRepeat(ref e, _) => {
             self.propagate_through_expr(&e, succ)
           }
 
@@ -1315,7 +1306,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             }
         }
         debug!("propagate_through_loop: using id for loop body {} {}",
-               expr.id, block_to_string(body));
+               expr.id, self.ir.tcx.map.node_to_pretty_string(body.id));
 
         let cond_ln = match kind {
             LoopLoop => ln,
@@ -1443,7 +1434,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                  sp: Span,
                  fk: FnKind,
                  entry_ln: LiveNode,
-                 body: &hir::Expr)
+                 body: &hir::Body)
     {
         let fn_ty = if let FnKind::Closure(_) = fk {
             self.ir.tcx.tables().node_id_to_type(id)
@@ -1460,7 +1451,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         // and must outlive the *call-site* of the function.
         let fn_ret =
             self.ir.tcx.liberate_late_bound_regions(
-                self.ir.tcx.region_maps.call_site_extent(id, body.id),
+                self.ir.tcx.region_maps.call_site_extent(id, body.value.id),
                 &fn_ret);
 
         if !fn_ret.is_never() && self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
@@ -1510,8 +1501,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         }
     }
 
-    fn warn_about_unused_args(&self, decl: &hir::FnDecl, entry_ln: LiveNode) {
-        for arg in &decl.inputs {
+    fn warn_about_unused_args(&self, body: &hir::Body, entry_ln: LiveNode) {
+        for arg in &body.arguments {
             arg.pat.each_binding(|_bm, p_id, sp, path1| {
                 let var = self.variable(p_id, sp);
                 // Ignore unused self.
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 4c3b102e54039..2d88567b8b873 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -73,7 +73,6 @@ use self::Aliasability::*;
 use hir::def_id::DefId;
 use hir::map as ast_map;
 use infer::InferCtxt;
-use middle::const_qualif::ConstQualif;
 use hir::def::{Def, CtorKind};
 use ty::adjustment;
 use ty::{self, Ty, TyCtxt};
@@ -705,7 +704,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             };
 
             match fn_expr.node {
-                hir::ExprClosure(.., body_id, _) => body_id.node_id(),
+                hir::ExprClosure(.., body_id, _) => body_id.node_id,
                 _ => bug!()
             }
         };
@@ -773,23 +772,23 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                            span: Span,
                            expr_ty: Ty<'tcx>)
                            -> cmt<'tcx> {
-        let qualif = self.tcx().const_qualif_map.borrow().get(&id).cloned()
-                               .unwrap_or(ConstQualif::NOT_CONST);
+        let promotable = self.tcx().rvalue_promotable_to_static.borrow().get(&id).cloned()
+                                   .unwrap_or(false);
 
         // Only promote `[T; 0]` before an RFC for rvalue promotions
         // is accepted.
-        let qualif = match expr_ty.sty {
-            ty::TyArray(_, 0) => qualif,
-            _ => ConstQualif::NOT_CONST
+        let promotable = match expr_ty.sty {
+            ty::TyArray(_, 0) => true,
+            _ => promotable & false
         };
 
         // Compute maximum lifetime of this rvalue. This is 'static if
         // we can promote to a constant, otherwise equal to enclosing temp
         // lifetime.
-        let re = if qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
-            self.temporary_scope(id)
-        } else {
+        let re = if promotable {
             self.tcx().mk_region(ty::ReStatic)
+        } else {
+            self.temporary_scope(id)
         };
         let ret = self.cat_rvalue(id, span, re, expr_ty);
         debug!("cat_rvalue_node ret {:?}", ret);
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 2c4710f1e452b..ee841afc02169 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -166,9 +166,10 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
             }
             Some(ast_map::NodeTraitItem(trait_method)) => {
                 match trait_method.node {
-                    hir::ConstTraitItem(_, ref default) => default.is_some(),
-                    hir::MethodTraitItem(_, ref body) => body.is_some(),
-                    hir::TypeTraitItem(..) => false,
+                    hir::TraitItemKind::Const(_, ref default) => default.is_some(),
+                    hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => true,
+                    hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
+                    hir::TraitItemKind::Type(..) => false,
                 }
             }
             Some(ast_map::NodeImplItem(impl_item)) => {
@@ -250,15 +251,15 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                 match item.node {
                     hir::ItemFn(.., body) => {
                         if item_might_be_inlined(&item) {
-                            self.visit_body(body);
+                            self.visit_nested_body(body);
                         }
                     }
 
                     // Reachable constants will be inlined into other crates
                     // unconditionally, so we need to make sure that their
                     // contents are also reachable.
-                    hir::ItemConst(_, ref init) => {
-                        self.visit_expr(&init);
+                    hir::ItemConst(_, init) => {
+                        self.visit_nested_body(init);
                     }
 
                     // These are normal, nothing reachable about these
@@ -274,28 +275,26 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
             }
             ast_map::NodeTraitItem(trait_method) => {
                 match trait_method.node {
-                    hir::ConstTraitItem(_, None) |
-                    hir::MethodTraitItem(_, None) => {
+                    hir::TraitItemKind::Const(_, None) |
+                    hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) => {
                         // Keep going, nothing to get exported
                     }
-                    hir::ConstTraitItem(_, Some(ref body)) => {
-                        self.visit_expr(body);
+                    hir::TraitItemKind::Const(_, Some(body_id)) |
+                    hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)) => {
+                        self.visit_nested_body(body_id);
                     }
-                    hir::MethodTraitItem(_, Some(body_id)) => {
-                        self.visit_body(body_id);
-                    }
-                    hir::TypeTraitItem(..) => {}
+                    hir::TraitItemKind::Type(..) => {}
                 }
             }
             ast_map::NodeImplItem(impl_item) => {
                 match impl_item.node {
-                    hir::ImplItemKind::Const(_, ref expr) => {
-                        self.visit_expr(&expr);
+                    hir::ImplItemKind::Const(_, body) => {
+                        self.visit_nested_body(body);
                     }
                     hir::ImplItemKind::Method(ref sig, body) => {
                         let did = self.tcx.map.get_parent_did(search_item);
                         if method_might_be_inlined(self.tcx, sig, impl_item, did) {
-                            self.visit_body(body)
+                            self.visit_nested_body(body)
                         }
                     }
                     hir::ImplItemKind::Type(_) => {}
@@ -358,6 +357,8 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a,
         }
     }
 
+    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {}
+
     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
         // processed in visit_item above
     }
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index b1e35e54eb9bb..faf4a448b7a84 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -1088,7 +1088,7 @@ fn resolve_item_like<'a, 'tcx, F>(visitor: &mut RegionResolutionVisitor<'tcx, 'a
 fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
                         kind: FnKind<'tcx>,
                         decl: &'tcx hir::FnDecl,
-                        body_id: hir::ExprId,
+                        body_id: hir::BodyId,
                         sp: Span,
                         id: ast::NodeId) {
     debug!("region::resolve_fn(id={:?}, \
@@ -1101,22 +1101,22 @@ fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
            visitor.cx.parent);
 
     visitor.cx.parent = visitor.new_code_extent(
-        CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id() });
+        CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id });
 
     let fn_decl_scope = visitor.new_code_extent(
-        CodeExtentData::ParameterScope { fn_id: id, body_id: body_id.node_id() });
+        CodeExtentData::ParameterScope { fn_id: id, body_id: body_id.node_id });
 
     if let Some(root_id) = visitor.cx.root_id {
-        visitor.region_maps.record_fn_parent(body_id.node_id(), root_id);
+        visitor.region_maps.record_fn_parent(body_id.node_id, root_id);
     }
 
     let outer_cx = visitor.cx;
     let outer_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet());
-    visitor.terminating_scopes.insert(body_id.node_id());
+    visitor.terminating_scopes.insert(body_id.node_id);
 
     // The arguments and `self` are parented to the fn.
     visitor.cx = Context {
-        root_id: Some(body_id.node_id()),
+        root_id: Some(body_id.node_id),
         parent: ROOT_CODE_EXTENT,
         var_parent: fn_decl_scope,
     };
@@ -1126,11 +1126,11 @@ fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
 
     // The body of the every fn is a root scope.
     visitor.cx = Context {
-        root_id: Some(body_id.node_id()),
+        root_id: Some(body_id.node_id),
         parent: fn_decl_scope,
         var_parent: fn_decl_scope
     };
-    visitor.visit_body(body_id);
+    visitor.visit_nested_body(body_id);
 
     // Restore context we had at the start.
     visitor.cx = outer_cx;
@@ -1195,7 +1195,7 @@ impl<'ast, 'a> Visitor<'ast> for RegionResolutionVisitor<'ast, 'a> {
     }
 
     fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl,
-                b: hir::ExprId, s: Span, n: NodeId) {
+                b: hir::BodyId, s: Span, n: NodeId) {
         resolve_fn(self, fk, fd, b, s, n);
     }
     fn visit_arm(&mut self, a: &'ast Arm) {
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index c5b03a4a32add..c491af972acbc 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -33,7 +33,6 @@ use util::nodemap::NodeMap;
 
 use rustc_data_structures::fx::FxHashSet;
 use hir;
-use hir::print::lifetime_to_string;
 use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
@@ -190,7 +189,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         // Items always introduce a new root scope
         self.with(RootScope, |_, this| {
             match item.node {
-                hir::ForeignItemFn(ref decl, ref generics) => {
+                hir::ForeignItemFn(ref decl, _, ref generics) => {
                     this.visit_early_late(item.id, decl, generics, |this| {
                         intravisit::walk_foreign_item(this, item);
                     })
@@ -206,7 +205,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fk: FnKind<'tcx>, decl: &'tcx hir::FnDecl,
-                b: hir::ExprId, s: Span, fn_id: ast::NodeId) {
+                b: hir::BodyId, s: Span, fn_id: ast::NodeId) {
         match fk {
             FnKind::ItemFn(_, generics, ..) => {
                 self.visit_early_late(fn_id,decl, generics, |this| {
@@ -266,7 +265,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
         // methods in an impl can reuse label names.
         let saved = replace(&mut self.labels_in_fn, vec![]);
 
-        if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
+        if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) =
+                trait_item.node {
             self.visit_early_late(
                 trait_item.id,
                 &sig.decl, &sig.generics,
@@ -407,7 +407,7 @@ fn signal_shadowing_problem(sess: &Session, name: ast::Name, orig: Original, sha
 
 // Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
 // if one of the label shadows a lifetime or another label.
-fn extract_labels(ctxt: &mut LifetimeContext, b: hir::ExprId) {
+fn extract_labels(ctxt: &mut LifetimeContext, b: hir::BodyId) {
     struct GatherLabels<'a> {
         sess: &'a Session,
         scope: Scope<'a>,
@@ -419,7 +419,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: hir::ExprId) {
         scope: ctxt.scope,
         labels_in_fn: &mut ctxt.labels_in_fn,
     };
-    gather.visit_expr(ctxt.hir_map.expr(b));
+    gather.visit_body(ctxt.hir_map.body(b));
     return;
 
     impl<'v, 'a> Visitor<'v> for GatherLabels<'a> {
@@ -501,7 +501,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
     fn add_scope_and_walk_fn(&mut self,
                              fk: FnKind<'tcx>,
                              fd: &'tcx hir::FnDecl,
-                             fb: hir::ExprId,
+                             fb: hir::BodyId,
                              _span: Span,
                              fn_id: ast::NodeId) {
         match fk {
@@ -522,8 +522,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         // `self.labels_in_fn`.
         extract_labels(self, fb);
 
-        self.with(FnScope { fn_id: fn_id, body_id: fb.node_id(), s: self.scope },
-                  |_old_scope, this| this.visit_body(fb))
+        self.with(FnScope { fn_id: fn_id, body_id: fb.node_id, s: self.scope },
+                  |_old_scope, this| this.visit_nested_body(fb))
     }
 
     // FIXME(#37666) this works around a limitation in the region inferencer
@@ -821,9 +821,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                        probably a bug in syntax::fold");
         }
 
-        debug!("lifetime_ref={:?} id={:?} resolved to {:?} span={:?}",
-               lifetime_to_string(lifetime_ref),
-               lifetime_ref.id,
+        debug!("{} resolved to {:?} span={:?}",
+               self.hir_map.node_to_string(lifetime_ref.id),
                def,
                self.sess.codemap().span_to_string(lifetime_ref.span));
         self.map.defs.insert(lifetime_ref.id, def);
@@ -860,8 +859,8 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
     debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl, generics);
 
     let mut constrained_by_input = ConstrainedCollector { regions: FxHashSet() };
-    for arg in &decl.inputs {
-        constrained_by_input.visit_ty(&arg.ty);
+    for arg_ty in &decl.inputs {
+        constrained_by_input.visit_ty(arg_ty);
     }
 
     let mut appears_in_output = AllCollector {
diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs
index 3576ae662a005..3c5a91f4ff04c 100644
--- a/src/librustc/mir/transform.rs
+++ b/src/librustc/mir/transform.rs
@@ -48,7 +48,7 @@ impl<'a, 'tcx> MirSource {
 
         match tcx.map.get(id) {
             map::NodeItem(&Item { node: ItemConst(..), .. }) |
-            map::NodeTraitItem(&TraitItem { node: ConstTraitItem(..), .. }) |
+            map::NodeTraitItem(&TraitItem { node: TraitItemKind::Const(..), .. }) |
             map::NodeImplItem(&ImplItem { node: ImplItemKind::Const(..), .. }) => {
                 MirSource::Const(id)
             }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index f24ff98035532..cb1fc15c5f682 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -508,14 +508,6 @@ pub struct GlobalCtxt<'tcx> {
     /// FIXME(arielb1): why is this separate from populated_external_types?
     pub populated_external_primitive_impls: RefCell<DefIdSet>,
 
-    /// Cache used by const_eval when decoding external constants.
-    /// Contains `None` when the constant has been fetched but doesn't exist.
-    /// Constains `Some(expr_id, type)` otherwise.
-    /// `type` is `None` in case it's not a primitive type
-    pub extern_const_statics: RefCell<DefIdMap<Option<(NodeId, Option<Ty<'tcx>>)>>>,
-    /// Cache used by const_eval when decoding extern const fns
-    pub extern_const_fns: RefCell<DefIdMap<NodeId>>,
-
     /// Maps any item's def-id to its stability index.
     pub stability: RefCell<stability::Index<'tcx>>,
 
@@ -537,8 +529,8 @@ pub struct GlobalCtxt<'tcx> {
     /// Caches the representation hints for struct definitions.
     repr_hint_cache: RefCell<DepTrackingMap<maps::ReprHints<'tcx>>>,
 
-    /// Maps Expr NodeId's to their constant qualification.
-    pub const_qualif_map: RefCell<NodeMap<middle::const_qualif::ConstQualif>>,
+    /// Maps Expr NodeId's to `true` iff `&expr` can have 'static lifetime.
+    pub rvalue_promotable_to_static: RefCell<NodeMap<bool>>,
 
     /// Caches CoerceUnsized kinds for impls on custom types.
     pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::adjustment::CustomCoerceUnsized>>,
@@ -787,13 +779,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             used_trait_imports: RefCell::new(NodeSet()),
             populated_external_types: RefCell::new(DefIdSet()),
             populated_external_primitive_impls: RefCell::new(DefIdSet()),
-            extern_const_statics: RefCell::new(DefIdMap()),
-            extern_const_fns: RefCell::new(DefIdMap()),
             stability: RefCell::new(stability),
             selection_cache: traits::SelectionCache::new(),
             evaluation_cache: traits::EvaluationCache::new(),
             repr_hint_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
-            const_qualif_map: RefCell::new(NodeMap()),
+            rvalue_promotable_to_static: RefCell::new(NodeMap()),
             custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
             cast_kinds: RefCell::new(NodeMap()),
             fragment_infos: RefCell::new(DefIdMap()),
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 2ab10d0446b2a..b03a432de4131 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1206,13 +1206,13 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                         tcx.construct_parameter_environment(
                             impl_item.span,
                             tcx.map.local_def_id(id),
-                            tcx.region_maps.call_site_extent(id, body.node_id()))
+                            tcx.region_maps.call_site_extent(id, body.node_id))
                     }
                 }
             }
             Some(ast_map::NodeTraitItem(trait_item)) => {
                 match trait_item.node {
-                    hir::TypeTraitItem(..) | hir::ConstTraitItem(..) => {
+                    hir::TraitItemKind::Type(..) | hir::TraitItemKind::Const(..) => {
                         // associated types don't have their own entry (for some reason),
                         // so for now just grab environment for the trait
                         let trait_id = tcx.map.get_parent(id);
@@ -1221,13 +1221,13 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                                                             trait_def_id,
                                                             tcx.region_maps.item_extent(id))
                     }
-                    hir::MethodTraitItem(_, ref body) => {
+                    hir::TraitItemKind::Method(_, ref body) => {
                         // Use call-site for extent (unless this is a
                         // trait method with no default; then fallback
                         // to the method id).
-                        let extent = if let Some(body_id) = *body {
+                        let extent = if let hir::TraitMethod::Provided(body_id) = *body {
                             // default impl: use call_site extent as free_id_outlive bound.
-                            tcx.region_maps.call_site_extent(id, body_id.node_id())
+                            tcx.region_maps.call_site_extent(id, body_id.node_id)
                         } else {
                             // no default impl: use item extent as free_id_outlive bound.
                             tcx.region_maps.item_extent(id)
@@ -1248,7 +1248,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                         tcx.construct_parameter_environment(
                             item.span,
                             fn_def_id,
-                            tcx.region_maps.call_site_extent(id, body_id.node_id()))
+                            tcx.region_maps.call_site_extent(id, body_id.node_id))
                     }
                     hir::ItemEnum(..) |
                     hir::ItemStruct(..) |
@@ -1284,7 +1284,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                     tcx.construct_parameter_environment(
                         expr.span,
                         base_def_id,
-                        tcx.region_maps.call_site_extent(id, body.node_id()))
+                        tcx.region_maps.call_site_extent(id, body.node_id))
                 } else {
                     tcx.empty_parameter_environment()
                 }
@@ -2100,10 +2100,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
 
-                hir::ItemTrait(.., ref trait_items) => {
-                    for trait_item in trait_items {
+                hir::ItemTrait(.., ref trait_item_refs) => {
+                    for trait_item_ref in trait_item_refs {
                         let assoc_item =
-                            self.associated_item_from_trait_item_ref(parent_def_id, trait_item);
+                            self.associated_item_from_trait_item_ref(parent_def_id, trait_item_ref);
                         self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item);
                     }
                 }
@@ -2121,28 +2121,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     fn associated_item_from_trait_item_ref(self,
                                            parent_def_id: DefId,
-                                           trait_item: &hir::TraitItem)
+                                           trait_item_ref: &hir::TraitItemRef)
                                            -> AssociatedItem {
-        let def_id = self.map.local_def_id(trait_item.id);
-
-        let (kind, has_self, has_value) = match trait_item.node {
-            hir::MethodTraitItem(ref sig, ref body) => {
-                (AssociatedKind::Method, sig.decl.get_self().is_some(),
-                 body.is_some())
-            }
-            hir::ConstTraitItem(_, ref value) => {
-                (AssociatedKind::Const, false, value.is_some())
-            }
-            hir::TypeTraitItem(_, ref ty) => {
-                (AssociatedKind::Type, false, ty.is_some())
+        let def_id = self.map.local_def_id(trait_item_ref.id.node_id);
+        let (kind, has_self) = match trait_item_ref.kind {
+            hir::AssociatedItemKind::Const => (ty::AssociatedKind::Const, false),
+            hir::AssociatedItemKind::Method { has_self } => {
+                (ty::AssociatedKind::Method, has_self)
             }
+            hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false),
         };
 
         AssociatedItem {
-            name: trait_item.name,
+            name: trait_item_ref.name,
             kind: kind,
-            vis: Visibility::from_hir(&hir::Inherited, trait_item.id, self),
-            defaultness: hir::Defaultness::Default { has_value: has_value },
+            vis: Visibility::from_hir(&hir::Inherited, trait_item_ref.id.node_id, self),
+            defaultness: trait_item_ref.defaultness,
             def_id: def_id,
             container: TraitContainer(parent_def_id),
             method_has_self_argument: has_self
@@ -2187,11 +2181,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             let id = self.map.as_local_node_id(def_id).unwrap();
             let item = self.map.expect_item(id);
             let vec: Vec<_> = match item.node {
-                hir::ItemTrait(.., ref trait_items) => {
-                    trait_items.iter()
-                               .map(|trait_item| trait_item.id)
-                               .map(|id| self.map.local_def_id(id))
-                               .collect()
+                hir::ItemTrait(.., ref trait_item_refs) => {
+                    trait_item_refs.iter()
+                                   .map(|trait_item_ref| trait_item_ref.id)
+                                   .map(|id| self.map.local_def_id(id.node_id))
+                                   .collect()
                 }
                 hir::ItemImpl(.., ref impl_item_refs) => {
                     impl_item_refs.iter()
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index 5ed628d7dcae5..dc2214dd34e72 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -189,9 +189,8 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                      move_data: &move_data::FlowedMoveData<'c, 'tcx>,
                                      all_loans: &[Loan<'tcx>],
                                      fn_id: ast::NodeId,
-                                     decl: &hir::FnDecl,
-                                     body: &hir::Expr) {
-    debug!("check_loans(body id={})", body.id);
+                                     body: &hir::Body) {
+    debug!("check_loans(body id={})", body.value.id);
 
     let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
     let infcx = bccx.tcx.borrowck_fake_infer_ctxt(param_env);
@@ -202,7 +201,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         all_loans: all_loans,
         param_env: &infcx.parameter_environment
     };
-    euv::ExprUseVisitor::new(&mut clcx, &infcx).walk_fn(decl, body);
+    euv::ExprUseVisitor::new(&mut clcx, &infcx).consume_body(body);
 }
 
 #[derive(PartialEq)]
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 5d59b58b847d9..34f1ad57c6211 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -41,21 +41,20 @@ mod move_error;
 
 pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                     fn_id: NodeId,
-                                    decl: &hir::FnDecl,
-                                    body: &hir::Expr)
+                                    body: &hir::Body)
                                     -> (Vec<Loan<'tcx>>,
                                         move_data::MoveData<'tcx>) {
     let mut glcx = GatherLoanCtxt {
         bccx: bccx,
         all_loans: Vec::new(),
-        item_ub: bccx.tcx.region_maps.node_extent(body.id),
+        item_ub: bccx.tcx.region_maps.node_extent(body.value.id),
         move_data: MoveData::new(),
         move_error_collector: move_error::MoveErrorCollector::new(),
     };
 
     let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
     let infcx = bccx.tcx.borrowck_fake_infer_ctxt(param_env);
-    euv::ExprUseVisitor::new(&mut glcx, &infcx).walk_fn(decl, body);
+    euv::ExprUseVisitor::new(&mut glcx, &infcx).consume_body(body);
 
     glcx.report_potential_errors();
     let GatherLoanCtxt { all_loans, move_data, .. } = glcx;
@@ -548,14 +547,14 @@ impl<'a, 'tcx> Visitor<'tcx> for StaticInitializerCtxt<'a, 'tcx> {
 
 pub fn gather_loans_in_static_initializer<'a, 'tcx>(bccx: &mut BorrowckCtxt<'a, 'tcx>,
                                                     item_id: ast::NodeId,
-                                                    expr: &'tcx hir::Expr) {
+                                                    body: hir::BodyId) {
 
-    debug!("gather_loans_in_static_initializer(expr={:?})", expr);
+    debug!("gather_loans_in_static_initializer(expr={:?})", body);
 
     let mut sicx = StaticInitializerCtxt {
         bccx: bccx,
         item_id: item_id
     };
 
-    sicx.visit_expr(expr);
+    sicx.visit_nested_body(body);
 }
diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs
index 9035c2ab3c236..c3ff564121c56 100644
--- a/src/librustc_borrowck/borrowck/mir/mod.rs
+++ b/src/librustc_borrowck/borrowck/mir/mod.rs
@@ -11,10 +11,7 @@
 use borrowck::BorrowckCtxt;
 
 use syntax::ast::{self, MetaItem};
-use syntax_pos::{Span, DUMMY_SP};
-
-use rustc::hir;
-use rustc::hir::intravisit::{FnKind};
+use syntax_pos::DUMMY_SP;
 
 use rustc::mir::{self, BasicBlock, BasicBlockData, Mir, Statement, Terminator, Location};
 use rustc::session::Session;
@@ -55,27 +52,14 @@ pub struct MoveDataParamEnv<'tcx> {
 }
 
 pub fn borrowck_mir(bcx: &mut BorrowckCtxt,
-                    fk: FnKind,
-                    _decl: &hir::FnDecl,
-                    body: &hir::Expr,
-                    _sp: Span,
                     id: ast::NodeId,
                     attributes: &[ast::Attribute]) {
-    match fk {
-        FnKind::ItemFn(name, ..) |
-        FnKind::Method(name, ..) => {
-            debug!("borrowck_mir({}) UNIMPLEMENTED", name);
-        }
-        FnKind::Closure(_) => {
-            debug!("borrowck_mir closure (body.id={}) UNIMPLEMENTED", body.id);
-        }
-    }
-
     let tcx = bcx.tcx;
-    let param_env = ty::ParameterEnvironment::for_item(tcx, id);
-
-    let mir = &tcx.item_mir(tcx.map.local_def_id(id));
+    let def_id = tcx.map.local_def_id(id);
+    debug!("borrowck_mir({}) UNIMPLEMENTED", tcx.item_path_str(def_id));
 
+    let mir = &tcx.item_mir(def_id);
+    let param_env = ty::ParameterEnvironment::for_item(tcx, id);
     let move_data = MoveData::gather_moves(mir, tcx, &param_env);
     let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
     let flow_inits =
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index ecf5c3ef176e5..1ba313015d596 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -68,7 +68,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
-                b: hir::ExprId, s: Span, id: ast::NodeId) {
+                b: hir::BodyId, s: Span, id: ast::NodeId) {
         match fk {
             FnKind::ItemFn(..) |
             FnKind::Method(..) => {
@@ -88,15 +88,15 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> {
     }
 
     fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
-        if let hir::ConstTraitItem(_, Some(ref expr)) = ti.node {
-            gather_loans::gather_loans_in_static_initializer(self, ti.id, &expr);
+        if let hir::TraitItemKind::Const(_, Some(expr)) = ti.node {
+            gather_loans::gather_loans_in_static_initializer(self, ti.id, expr);
         }
         intravisit::walk_trait_item(self, ti);
     }
 
     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
-        if let hir::ImplItemKind::Const(_, ref expr) = ii.node {
-            gather_loans::gather_loans_in_static_initializer(self, ii.id, &expr);
+        if let hir::ImplItemKind::Const(_, expr) = ii.node {
+            gather_loans::gather_loans_in_static_initializer(self, ii.id, expr);
         }
         intravisit::walk_impl_item(self, ii);
     }
@@ -141,9 +141,9 @@ fn borrowck_item<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, item: &'tcx hir::I
     // loan step is intended for things that have a data
     // flow dependent conditions.
     match item.node {
-        hir::ItemStatic(.., ref ex) |
-        hir::ItemConst(_, ref ex) => {
-            gather_loans::gather_loans_in_static_initializer(this, item.id, &ex);
+        hir::ItemStatic(.., ex) |
+        hir::ItemConst(_, ex) => {
+            gather_loans::gather_loans_in_static_initializer(this, item.id, ex);
         }
         _ => { }
     }
@@ -161,25 +161,25 @@ pub struct AnalysisData<'a, 'tcx: 'a> {
 fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
                          fk: FnKind<'tcx>,
                          decl: &'tcx hir::FnDecl,
-                         body_id: hir::ExprId,
+                         body_id: hir::BodyId,
                          sp: Span,
                          id: ast::NodeId,
                          attributes: &[ast::Attribute]) {
     debug!("borrowck_fn(id={})", id);
 
-    let body = this.tcx.map.expr(body_id);
+    let body = this.tcx.map.body(body_id);
 
     if attributes.iter().any(|item| item.check_name("rustc_mir_borrowck")) {
         this.with_temp_region_map(id, |this| {
-            mir::borrowck_mir(this, fk, decl, body, sp, id, attributes)
+            mir::borrowck_mir(this, id, attributes)
         });
     }
 
-    let cfg = cfg::CFG::new(this.tcx, body);
+    let cfg = cfg::CFG::new(this.tcx, &body.value);
     let AnalysisData { all_loans,
                        loans: loan_dfcx,
                        move_data: flowed_moves } =
-        build_borrowck_dataflow_data(this, fk, decl, &cfg, body, sp, id);
+        build_borrowck_dataflow_data(this, &cfg, body, id);
 
     move_data::fragments::instrument_move_fragments(&flowed_moves.move_data,
                                                     this.tcx,
@@ -194,31 +194,31 @@ fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
                              &flowed_moves,
                              &all_loans[..],
                              id,
-                             decl,
                              body);
 
     intravisit::walk_fn(this, fk, decl, body_id, sp, id);
 }
 
 fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
-                                          fk: FnKind<'tcx>,
-                                          decl: &'tcx hir::FnDecl,
                                           cfg: &cfg::CFG,
-                                          body: &'tcx hir::Expr,
-                                          sp: Span,
+                                          body: &'tcx hir::Body,
                                           id: ast::NodeId)
                                           -> AnalysisData<'a, 'tcx>
 {
     // Check the body of fn items.
     let tcx = this.tcx;
-    let id_range = intravisit::compute_id_range_for_fn_body(fk, decl, body, sp, id, &tcx.map);
+    let id_range = {
+        let mut visitor = intravisit::IdRangeComputingVisitor::new(&tcx.map);
+        visitor.visit_body(body);
+        visitor.result()
+    };
     let (all_loans, move_data) =
-        gather_loans::gather_loans_in_fn(this, id, decl, body);
+        gather_loans::gather_loans_in_fn(this, id, body);
 
     let mut loan_dfcx =
         DataFlowContext::new(this.tcx,
                              "borrowck",
-                             Some(decl),
+                             Some(body),
                              cfg,
                              LoanDataFlowOperator,
                              id_range,
@@ -235,7 +235,6 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
                                                       this.tcx,
                                                       cfg,
                                                       id_range,
-                                                      decl,
                                                       body);
 
     AnalysisData { all_loans: all_loans,
@@ -263,14 +262,11 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
         }
     };
 
-    let body = tcx.map.expr(fn_parts.body);
+    let body = tcx.map.body(fn_parts.body);
 
     let dataflow_data = build_borrowck_dataflow_data(&mut bccx,
-                                                     fn_parts.kind,
-                                                     &fn_parts.decl,
                                                      cfg,
                                                      body,
-                                                     fn_parts.span,
                                                      fn_parts.id);
 
     (bccx, dataflow_data)
@@ -416,7 +412,7 @@ pub fn closure_to_block(closure_id: ast::NodeId,
     match tcx.map.get(closure_id) {
         hir_map::NodeExpr(expr) => match expr.node {
             hir::ExprClosure(.., body_id, _) => {
-                body_id.node_id()
+                body_id.node_id
             }
             _ => {
                 bug!("encountered non-closure id: {}", closure_id)
@@ -1121,22 +1117,21 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                 if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat {
                     if let Categorization::Local(local_id) = inner_cmt.cat {
                         let parent = self.tcx.map.get_parent_node(local_id);
-                        let opt_fn_decl = FnLikeNode::from_node(self.tcx.map.get(parent))
-                            .map(|fn_like| fn_like.decl());
 
-                        if let Some(fn_decl) = opt_fn_decl {
-                            if let Some(ref arg) = fn_decl.inputs.iter()
-                                .find(|ref arg| arg.pat.id == local_id) {
+                        if let Some(fn_like) = FnLikeNode::from_node(self.tcx.map.get(parent)) {
+                            if let Some(i) = self.tcx.map.body(fn_like.body()).arguments.iter()
+                                                     .position(|arg| arg.pat.id == local_id) {
+                                let arg_ty = &fn_like.decl().inputs[i];
                                 if let hir::TyRptr(
                                     opt_lifetime,
                                     hir::MutTy{mutbl: hir::Mutability::MutImmutable, ref ty}) =
-                                    arg.ty.node {
+                                    arg_ty.node {
                                     if let Some(lifetime) = opt_lifetime {
                                         if let Ok(snippet) = self.tcx.sess.codemap()
                                             .span_to_snippet(ty.span) {
                                             if let Ok(lifetime_snippet) = self.tcx.sess.codemap()
                                                 .span_to_snippet(lifetime.span) {
-                                                    db.span_label(arg.ty.span,
+                                                    db.span_label(arg_ty.span,
                                                                   &format!("use `&{} mut {}` \
                                                                             here to make mutable",
                                                                             lifetime_snippet,
@@ -1145,9 +1140,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                                         }
                                     }
                                     else if let Ok(snippet) = self.tcx.sess.codemap()
-                                        .span_to_snippet(arg.ty.span) {
+                                        .span_to_snippet(arg_ty.span) {
                                         if snippet.starts_with("&") {
-                                            db.span_label(arg.ty.span,
+                                            db.span_label(arg_ty.span,
                                                           &format!("use `{}` here to make mutable",
                                                                    snippet.replace("&", "&mut ")));
                                         }
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index 32bda5e11620a..a02aba7208c7f 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -655,13 +655,12 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
                tcx: TyCtxt<'a, 'tcx, 'tcx>,
                cfg: &cfg::CFG,
                id_range: IdRange,
-               decl: &hir::FnDecl,
-               body: &hir::Expr)
+               body: &hir::Body)
                -> FlowedMoveData<'a, 'tcx> {
         let mut dfcx_moves =
             DataFlowContext::new(tcx,
                                  "flowed_move_data_moves",
-                                 Some(decl),
+                                 Some(body),
                                  cfg,
                                  MoveDataFlowOperator,
                                  id_range,
@@ -669,7 +668,7 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
         let mut dfcx_assign =
             DataFlowContext::new(tcx,
                                  "flowed_move_data_assigns",
-                                 Some(decl),
+                                 Some(body),
                                  cfg,
                                  AssignDataFlowOperator,
                                  id_range,
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 786b59e818da2..01b19e1f53979 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -30,7 +30,6 @@ use rustc_errors::DiagnosticBuilder;
 
 use rustc::hir::def::*;
 use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
-use rustc::hir::print::pat_to_string;
 use rustc::hir::{self, Pat, PatKind};
 
 use rustc_back::slice;
@@ -43,39 +42,17 @@ struct OuterVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
 
 impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_expr(&mut self, _expr: &'tcx hir::Expr) {
-        return // const, static and N in [T; N] - shouldn't contain anything
-    }
-
-    fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
-        if let hir::ConstTraitItem(..) = item.node {
-            return // nothing worth match checking in a constant
-        } else {
-            intravisit::walk_trait_item(self, item);
-        }
-    }
-
-    fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
-        if let hir::ImplItemKind::Const(..) = item.node {
-            return // nothing worth match checking in a constant
-        } else {
-            intravisit::walk_impl_item(self, item);
-        }
+        NestedVisitorMap::OnlyBodies(&self.tcx.map)
     }
 
     fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
-                b: hir::ExprId, s: Span, id: ast::NodeId) {
-        if let FnKind::Closure(..) = fk {
-            span_bug!(s, "check_match: closure outside of function")
-        }
+                b: hir::BodyId, s: Span, id: ast::NodeId) {
+        intravisit::walk_fn(self, fk, fd, b, s, id);
 
         MatchVisitor {
             tcx: self.tcx,
             param_env: &ty::ParameterEnvironment::for_item(self.tcx, id)
-        }.visit_fn(fk, fd, b, s, id);
+        }.visit_body(self.tcx.map.body(b));
     }
 }
 
@@ -96,7 +73,7 @@ struct MatchVisitor<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+        NestedVisitorMap::None
     }
 
     fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
@@ -119,13 +96,12 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
         self.check_patterns(false, slice::ref_slice(&loc.pat));
     }
 
-    fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
-                b: hir::ExprId, s: Span, n: ast::NodeId) {
-        intravisit::walk_fn(self, fk, fd, b, s, n);
+    fn visit_body(&mut self, body: &'tcx hir::Body) {
+        intravisit::walk_body(self, body);
 
-        for input in &fd.inputs {
-            self.check_irrefutable(&input.pat, true);
-            self.check_patterns(false, slice::ref_slice(&input.pat));
+        for arg in &body.arguments {
+            self.check_irrefutable(&arg.pat, true);
+            self.check_patterns(false, slice::ref_slice(&arg.pat));
         }
     }
 }
@@ -254,7 +230,9 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
                 Useful => bug!()
             };
 
-            let pattern_string = pat_to_string(witness[0].single_pattern());
+            let pattern_string = hir::print::to_string(&self.tcx.map, |s| {
+                s.print_pat(witness[0].single_pattern())
+            });
             let mut diag = struct_span_err!(
                 self.tcx.sess, pat.span, E0005,
                 "refutable pattern in {}: `{}` not covered",
@@ -405,7 +383,9 @@ fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                         },
                         _ => bug!(),
                     };
-                    let pattern_string = pat_to_string(witness);
+                    let pattern_string = hir::print::to_string(&cx.tcx.map, |s| {
+                        s.print_pat(witness)
+                    });
                     struct_span_err!(cx.tcx.sess, sp, E0297,
                         "refutable pattern in `for` loop binding: \
                                 `{}` not covered",
@@ -415,7 +395,7 @@ fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                 },
                 _ => {
                     let pattern_strings: Vec<_> = witnesses.iter().map(|w| {
-                        pat_to_string(w)
+                        hir::print::to_string(&cx.tcx.map, |s| s.print_pat(w))
                     }).collect();
                     const LIMIT: usize = 3;
                     let joined_patterns = match pattern_strings.len() {
diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs
index 83b0d9dec6d90..b24cd261dd584 100644
--- a/src/librustc_const_eval/diagnostics.rs
+++ b/src/librustc_const_eval/diagnostics.rs
@@ -576,18 +576,18 @@ https://doc.rust-lang.org/reference.html#ffi-attributes
 
 
 E0306: r##"
-In an array literal `[x; N]`, `N` is the number of elements in the array. This
+In an array type `[T; N]`, `N` is the number of elements in the array. This
 must be an unsigned integer. Erroneous code example:
 
 ```compile_fail,E0306
-let x = [0i32; true]; // error: expected positive integer for repeat count,
-                      //        found boolean
+const X: [i32; true] = [0]; // error: expected `usize` for array length,
+                            //        found boolean
 ```
 
 Working example:
 
 ```
-let x = [0i32; 2];
+const X: [i32; 1] = [0];
 ```
 "##,
 }
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 9fcab1239899f..e8e7a2eb7ede0 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -17,7 +17,6 @@ use self::EvalHint::*;
 
 use rustc::hir::map as ast_map;
 use rustc::hir::map::blocks::FnLikeNode;
-use rustc::middle::cstore::InlinedItem;
 use rustc::traits;
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
@@ -56,15 +55,17 @@ macro_rules! math {
 fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   variant_def: DefId)
                                   -> Option<&'tcx Expr> {
-    fn variant_expr<'a>(variants: &'a [hir::Variant], id: ast::NodeId)
-                        -> Option<&'a Expr> {
+    let variant_expr = |variants: &'tcx [hir::Variant], id: ast::NodeId |
+                        -> Option<&'tcx Expr> {
         for variant in variants {
             if variant.node.data.id() == id {
-                return variant.node.disr_expr.as_ref().map(|e| &**e);
+                return variant.node.disr_expr.map(|e| {
+                    &tcx.map.body(e).value
+                });
             }
         }
         None
-    }
+    };
 
     if let Some(variant_node_id) = tcx.map.as_local_node_id(variant_def) {
         let enum_node_id = tcx.map.get_parent(variant_node_id);
@@ -96,21 +97,24 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         match tcx.map.find(node_id) {
             None => None,
             Some(ast_map::NodeItem(it)) => match it.node {
-                hir::ItemConst(ref ty, ref const_expr) => {
-                    Some((&const_expr, tcx.ast_ty_to_prim_ty(ty)))
+                hir::ItemConst(ref ty, body) => {
+                    Some((&tcx.map.body(body).value,
+                          tcx.ast_ty_to_prim_ty(ty)))
                 }
                 _ => None
             },
             Some(ast_map::NodeTraitItem(ti)) => match ti.node {
-                hir::ConstTraitItem(ref ty, ref expr_option) => {
+                hir::TraitItemKind::Const(ref ty, default) => {
                     if let Some(substs) = substs {
                         // If we have a trait item and the substitutions for it,
                         // `resolve_trait_associated_const` will select an impl
                         // or the default.
                         let trait_id = tcx.map.get_parent(node_id);
                         let trait_id = tcx.map.local_def_id(trait_id);
-                        let default_value = expr_option.as_ref()
-                            .map(|expr| (&**expr, tcx.ast_ty_to_prim_ty(ty)));
+                        let default_value = default.map(|body| {
+                            (&tcx.map.body(body).value,
+                             tcx.ast_ty_to_prim_ty(ty))
+                        });
                         resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
                     } else {
                         // Technically, without knowing anything about the
@@ -125,29 +129,19 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 _ => None
             },
             Some(ast_map::NodeImplItem(ii)) => match ii.node {
-                hir::ImplItemKind::Const(ref ty, ref expr) => {
-                    Some((&expr, tcx.ast_ty_to_prim_ty(ty)))
+                hir::ImplItemKind::Const(ref ty, body) => {
+                    Some((&tcx.map.body(body).value,
+                          tcx.ast_ty_to_prim_ty(ty)))
                 }
                 _ => None
             },
             Some(_) => None
         }
     } else {
-        match tcx.extern_const_statics.borrow().get(&def_id) {
-            Some(&None) => return None,
-            Some(&Some((expr_id, ty))) => {
-                return Some((tcx.map.expect_expr(expr_id), ty));
-            }
-            None => {}
-        }
-        let mut used_substs = false;
-        let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
-            Some((&InlinedItem { body: ref const_expr, .. }, _)) => {
-                Some((&**const_expr, Some(tcx.sess.cstore.item_type(tcx, def_id))))
-            }
-            _ => None
-        };
-        let expr_ty = match tcx.sess.cstore.describe_def(def_id) {
+        let expr_ty = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
+            (&body.value, Some(tcx.sess.cstore.item_type(tcx, def_id)))
+        });
+        match tcx.sess.cstore.describe_def(def_id) {
             Some(Def::AssociatedConst(_)) => {
                 let trait_id = tcx.sess.cstore.trait_of_item(def_id);
                 // As mentioned in the comments above for in-crate
@@ -155,8 +149,6 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 // trait-associated const if the caller gives us the
                 // substitutions for the reference to it.
                 if let Some(trait_id) = trait_id {
-                    used_substs = true;
-
                     if let Some(substs) = substs {
                         resolve_trait_associated_const(tcx, def_id, expr_ty, trait_id, substs)
                     } else {
@@ -168,70 +160,27 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             },
             Some(Def::Const(..)) => expr_ty,
             _ => None
-        };
-        // If we used the substitutions, particularly to choose an impl
-        // of a trait-associated const, don't cache that, because the next
-        // lookup with the same def_id may yield a different result.
-        if !used_substs {
-            tcx.extern_const_statics
-               .borrow_mut()
-               .insert(def_id, expr_ty.map(|(e, t)| (e.id, t)));
         }
-        expr_ty
     }
 }
 
-fn inline_const_fn_from_external_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                                 def_id: DefId)
-                                                 -> Option<ast::NodeId> {
-    match tcx.extern_const_fns.borrow().get(&def_id) {
-        Some(&ast::DUMMY_NODE_ID) => return None,
-        Some(&fn_id) => return Some(fn_id),
-        None => {}
-    }
-
-    if !tcx.sess.cstore.is_const_fn(def_id) {
-        tcx.extern_const_fns.borrow_mut().insert(def_id, ast::DUMMY_NODE_ID);
-        return None;
-    }
-
-    let fn_id = tcx.sess.cstore.maybe_get_item_ast(tcx, def_id).map(|t| t.1);
-    tcx.extern_const_fns.borrow_mut().insert(def_id,
-                                             fn_id.unwrap_or(ast::DUMMY_NODE_ID));
-    fn_id
-}
-
-pub enum ConstFnNode<'tcx> {
-    Local(FnLikeNode<'tcx>),
-    Inlined(&'tcx InlinedItem)
-}
-
-pub fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-                                       -> Option<ConstFnNode<'tcx>>
+fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
+                                   -> Option<&'tcx hir::Body>
 {
-    let fn_id = if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
-        node_id
-    } else {
-        if let Some(fn_id) = inline_const_fn_from_external_crate(tcx, def_id) {
-            if let ast_map::NodeInlinedItem(ii) = tcx.map.get(fn_id) {
-                return Some(ConstFnNode::Inlined(ii));
+    if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
+        FnLikeNode::from_node(tcx.map.get(node_id)).and_then(|fn_like| {
+            if fn_like.constness() == hir::Constness::Const {
+                Some(tcx.map.body(fn_like.body()))
             } else {
-                bug!("Got const fn from external crate, but it's not inlined")
+                None
             }
+        })
+    } else {
+        if tcx.sess.cstore.is_const_fn(def_id) {
+            tcx.sess.cstore.maybe_get_item_body(tcx, def_id)
         } else {
-            return None;
+            None
         }
-    };
-
-    let fn_like = match FnLikeNode::from_node(tcx.map.get(fn_id)) {
-        Some(fn_like) => fn_like,
-        None => return None
-    };
-
-    if fn_like.constness() == hir::Constness::Const {
-        Some(ConstFnNode::Local(fn_like))
-    } else {
-        None
     }
 }
 
@@ -864,18 +813,15 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
               Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
               callee => signal!(e, CallOn(callee)),
           };
-          let (arg_defs, body_id) = match lookup_const_fn_by_id(tcx, did) {
-              Some(ConstFnNode::Inlined(ii)) => (ii.const_fn_args.clone(), ii.body.expr_id()),
-              Some(ConstFnNode::Local(fn_like)) =>
-                  (fn_like.decl().inputs.iter()
-                   .map(|arg| match arg.pat.node {
-                       hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
-                       _ => None
-                   }).collect(),
-                   fn_like.body()),
+          let body = match lookup_const_fn_by_id(tcx, did) {
+              Some(body) => body,
               None => signal!(e, NonConstPath),
           };
-          let result = tcx.map.expr(body_id);
+
+          let arg_defs = body.arguments.iter().map(|arg| match arg.pat.node {
+               hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
+               _ => None
+           }).collect::<Vec<_>>();
           assert_eq!(arg_defs.len(), args.len());
 
           let mut call_args = DefIdMap();
@@ -893,7 +839,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
               }
           }
           debug!("const call({:?})", call_args);
-          eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args))?
+          eval_const_expr_partial(tcx, &body.value, ty_hint, Some(&call_args))?
       },
       hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
           Ok(val) => val,
@@ -953,11 +899,12 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
       }
       hir::ExprArray(ref v) => Array(e.id, v.len() as u64),
-      hir::ExprRepeat(_, ref n) => {
+      hir::ExprRepeat(_, n) => {
           let len_hint = ty_hint.checked_or(tcx.types.usize);
+          let n = &tcx.map.body(n).value;
           Repeat(
               e.id,
-              match eval_const_expr_partial(tcx, &n, len_hint, fn_args)? {
+              match eval_const_expr_partial(tcx, n, len_hint, fn_args)? {
                   Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
                   Integral(_) => signal!(e, RepeatCountNotNatural),
                   _ => signal!(e, RepeatCountNotInt),
@@ -1373,7 +1320,8 @@ pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
             if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node {
                 if let Def::Local(..) = path.def {
-                    diag.note(&format!("`{}` is a variable", path));
+                    diag.note(&format!("`{}` is a variable",
+                                       tcx.map.node_to_pretty_string(count_expr.id)));
                 }
             }
 
diff --git a/src/librustc_driver/derive_registrar.rs b/src/librustc_driver/derive_registrar.rs
index 4db620b2bec3b..6a884bafce752 100644
--- a/src/librustc_driver/derive_registrar.rs
+++ b/src/librustc_driver/derive_registrar.rs
@@ -35,6 +35,9 @@ impl<'v> ItemLikeVisitor<'v> for Finder {
         }
     }
 
+    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+    }
+
     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
     }
 }
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 74df1e52bde43..5103a55fd71e1 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -47,7 +47,7 @@ use std::path::Path;
 use std::str::FromStr;
 
 use rustc::hir::map as hir_map;
-use rustc::hir::map::{blocks, NodePrinter};
+use rustc::hir::map::blocks;
 use rustc::hir;
 use rustc::hir::print as pprust_hir;
 
@@ -320,7 +320,16 @@ impl<'ast> HirPrinterSupport<'ast> for NoAnn<'ast> {
 }
 
 impl<'ast> pprust::PpAnn for NoAnn<'ast> {}
-impl<'ast> pprust_hir::PpAnn for NoAnn<'ast> {}
+impl<'ast> pprust_hir::PpAnn for NoAnn<'ast> {
+    fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
+              -> io::Result<()> {
+        if let Some(ref map) = self.ast_map {
+            pprust_hir::PpAnn::nested(map, state, nested)
+        } else {
+            Ok(())
+        }
+    }
+}
 
 struct IdentifiedAnnotation<'ast> {
     sess: &'ast Session,
@@ -393,6 +402,14 @@ impl<'ast> HirPrinterSupport<'ast> for IdentifiedAnnotation<'ast> {
 }
 
 impl<'ast> pprust_hir::PpAnn for IdentifiedAnnotation<'ast> {
+    fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
+              -> io::Result<()> {
+        if let Some(ref map) = self.ast_map {
+            pprust_hir::PpAnn::nested(map, state, nested)
+        } else {
+            Ok(())
+        }
+    }
     fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
         match node {
             pprust_hir::NodeExpr(_) => s.popen(),
@@ -488,6 +505,10 @@ impl<'b, 'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> {
 }
 
 impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> {
+    fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
+              -> io::Result<()> {
+        pprust_hir::PpAnn::nested(&self.tcx.map, state, nested)
+    }
     fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
         match node {
             pprust_hir::NodeExpr(_) => s.popen(),
@@ -702,8 +723,8 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
     let cfg = match code {
         blocks::Code::Expr(expr) => cfg::CFG::new(tcx, expr),
         blocks::Code::FnLike(fn_like) => {
-            let body = tcx.map.expr(fn_like.body());
-            cfg::CFG::new(tcx, body)
+            let body = tcx.map.body(fn_like.body());
+            cfg::CFG::new(tcx, &body.value)
         },
     };
     let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
@@ -909,11 +930,10 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                                                                          &mut rdr,
                                                                          box out,
                                                                          annotation.pp_ann(),
-                                                                         true,
-                                                                         Some(ast_map.krate()));
+                                                                         true);
                     for node_id in uii.all_matching_node_ids(ast_map) {
                         let node = ast_map.get(node_id);
-                        pp_state.print_node(&node)?;
+                        pp_state.print_node(node)?;
                         pp::space(&mut pp_state.s)?;
                         let path = annotation.node_path(node_id)
                             .expect("--unpretty missing node paths");
diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs
index 87e6b2befdc32..b5fe158f158ca 100644
--- a/src/librustc_incremental/assert_dep_graph.rs
+++ b/src/librustc_incremental/assert_dep_graph.rs
@@ -171,6 +171,10 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for IfThisChanged<'a, 'tcx> {
         self.process_attrs(item.id, &item.attrs);
     }
 
+    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
+        self.process_attrs(trait_item.id, &trait_item.attrs);
+    }
+
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
         self.process_attrs(impl_item.id, &impl_item.attrs);
     }
diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs
index 74707865dee4d..49609fbc7984f 100644
--- a/src/librustc_incremental/calculate_svh/mod.rs
+++ b/src/librustc_incremental/calculate_svh/mod.rs
@@ -234,6 +234,11 @@ impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
         visit::walk_item(self, item);
     }
 
+    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
+        self.calculate_node_id(trait_item.id, |v| v.visit_trait_item(trait_item));
+        visit::walk_trait_item(self, trait_item);
+    }
+
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
         self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item));
         visit::walk_impl_item(self, impl_item);
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index bb61756694fe5..4bb12667bbc14 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -188,7 +188,7 @@ enum SawAbiComponent<'a> {
     SawTraitItem(SawTraitOrImplItemComponent),
     SawImplItem(SawTraitOrImplItemComponent),
     SawStructField,
-    SawVariant,
+    SawVariant(bool),
     SawQPath,
     SawPathSegment,
     SawPathParameters,
@@ -473,12 +473,14 @@ enum SawTraitOrImplItemComponent {
     SawTraitOrImplItemType
 }
 
-fn saw_trait_item(ti: &TraitItem_) -> SawTraitOrImplItemComponent {
+fn saw_trait_item(ti: &TraitItemKind) -> SawTraitOrImplItemComponent {
     match *ti {
-        ConstTraitItem(..) => SawTraitOrImplItemConst,
-        MethodTraitItem(ref sig, ref body) =>
-            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, body.is_some()),
-        TypeTraitItem(..) => SawTraitOrImplItemType
+        TraitItemKind::Const(..) => SawTraitOrImplItemConst,
+        TraitItemKind::Method(ref sig, TraitMethod::Required(_)) =>
+            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, false),
+        TraitItemKind::Method(ref sig, TraitMethod::Provided(_)) =>
+            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true),
+        TraitItemKind::Type(..) => SawTraitOrImplItemType
     }
 }
 
@@ -584,7 +586,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
                      g: &'tcx Generics,
                      item_id: NodeId) {
         debug!("visit_variant: st={:?}", self.st);
-        SawVariant.hash(self.st);
+        SawVariant(v.node.disr_expr.is_some()).hash(self.st);
         hash_attrs!(self, &v.node.attrs);
         visit::walk_variant(self, v, g, item_id)
     }
@@ -616,7 +618,12 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
         // implicitly hashing the discriminant of SawExprComponent.
         hash_span!(self, ex.span, force_span);
         hash_attrs!(self, &ex.attrs);
-        visit::walk_expr(self, ex)
+
+        // Always hash nested constant bodies (e.g. n in `[x; n]`).
+        let hash_bodies = self.hash_bodies;
+        self.hash_bodies = true;
+        visit::walk_expr(self, ex);
+        self.hash_bodies = hash_bodies;
     }
 
     fn visit_stmt(&mut self, s: &'tcx Stmt) {
@@ -686,7 +693,12 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
         debug!("visit_ty: st={:?}", self.st);
         SawTy(saw_ty(&t.node)).hash(self.st);
         hash_span!(self, t.span);
-        visit::walk_ty(self, t)
+
+        // Always hash nested constant bodies (e.g. N in `[T; N]`).
+        let hash_bodies = self.hash_bodies;
+        self.hash_bodies = true;
+        visit::walk_ty(self, t);
+        self.hash_bodies = hash_bodies;
     }
 
     fn visit_generics(&mut self, g: &'tcx Generics) {
@@ -1157,8 +1169,9 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
             // These fields are handled separately:
             exported_macros: _,
             items: _,
+            trait_items: _,
             impl_items: _,
-            exprs: _,
+            bodies: _,
         } = *krate;
 
         visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index 40873011a7b8d..481462dff86e4 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -185,6 +185,9 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> {
         }
     }
 
+    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+    }
+
     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
     }
 }
@@ -229,6 +232,9 @@ impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx,
         }
     }
 
+    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+    }
+
     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
     }
 }
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index 1d384741d9660..2baef47c214c2 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -243,7 +243,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
                 cx: &LateContext,
                 fk: FnKind,
                 _: &hir::FnDecl,
-                _: &hir::Expr,
+                _: &hir::Body,
                 span: Span,
                 id: ast::NodeId) {
         match fk {
@@ -271,12 +271,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
         }
     }
 
-    fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
-        if let hir::MethodTraitItem(_, None) = trait_item.node {
+    fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
+        if let hir::TraitItemKind::Method(_, hir::TraitMethod::Required(ref names)) = item.node {
             self.check_snake_case(cx,
                                   "trait method",
-                                  &trait_item.name.as_str(),
-                                  Some(trait_item.span));
+                                  &item.name.as_str(),
+                                  Some(item.span));
+            for name in names {
+                self.check_snake_case(cx, "variable", &name.node.as_str(), Some(name.span));
+            }
         }
     }
 
@@ -288,14 +291,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
     }
 
     fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
-        // Exclude parameter names from foreign functions
-        let parent_node = cx.tcx.map.get_parent_node(p.id);
-        if let hir::map::NodeForeignItem(item) = cx.tcx.map.get(parent_node) {
-            if let hir::ForeignItemFn(..) = item.node {
-                return;
-            }
-        }
-
         if let &PatKind::Binding(_, _, ref path1, _) = &p.node {
             self.check_snake_case(cx, "variable", &path1.node.as_str(), Some(p.span));
         }
@@ -363,7 +358,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals {
 
     fn check_trait_item(&mut self, cx: &LateContext, ti: &hir::TraitItem) {
         match ti.node {
-            hir::ConstTraitItem(..) => {
+            hir::TraitItemKind::Const(..) => {
                 NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ti.name, ti.span);
             }
             _ => {}
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index cd414846af4fb..c021ffee81899 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -222,7 +222,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
                 cx: &LateContext,
                 fk: FnKind<'tcx>,
                 _: &hir::FnDecl,
-                _: &hir::Expr,
+                _: &hir::Body,
                 span: Span,
                 _: ast::NodeId) {
         match fk {
@@ -240,11 +240,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
         }
     }
 
-    fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
-        if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
+    fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
+        if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) = item.node {
             if sig.unsafety == hir::Unsafety::Unsafe {
                 cx.span_lint(UNSAFE_CODE,
-                             trait_item.span,
+                             item.span,
                              "declaration of an `unsafe` method")
             }
         }
@@ -374,12 +374,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
             hir::ItemEnum(..) => "an enum",
             hir::ItemStruct(..) => "a struct",
             hir::ItemUnion(..) => "a union",
-            hir::ItemTrait(.., ref items) => {
+            hir::ItemTrait(.., ref trait_item_refs) => {
                 // Issue #11592, traits are always considered exported, even when private.
                 if it.vis == hir::Visibility::Inherited {
                     self.private_traits.insert(it.id);
-                    for itm in items {
-                        self.private_traits.insert(itm.id);
+                    for trait_item_ref in trait_item_refs {
+                        self.private_traits.insert(trait_item_ref.id.node_id);
                     }
                     return;
                 }
@@ -418,9 +418,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
         }
 
         let desc = match trait_item.node {
-            hir::ConstTraitItem(..) => "an associated constant",
-            hir::MethodTraitItem(..) => "a trait method",
-            hir::TypeTraitItem(..) => "an associated type",
+            hir::TraitItemKind::Const(..) => "an associated constant",
+            hir::TraitItemKind::Method(..) => "a trait method",
+            hir::TraitItemKind::Type(..) => "an associated type",
         };
 
         self.check_missing_docs_attrs(cx,
@@ -674,7 +674,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
                 cx: &LateContext,
                 fn_kind: FnKind,
                 _: &hir::FnDecl,
-                blk: &hir::Expr,
+                body: &hir::Body,
                 sp: Span,
                 id: ast::NodeId) {
         let method = match fn_kind {
@@ -712,7 +712,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
         // to have behaviour like the above, rather than
         // e.g. accidentally recurring after an assert.
 
-        let cfg = cfg::CFG::new(cx.tcx, blk);
+        let cfg = cfg::CFG::new(cx.tcx, &body.value);
 
         let mut work_queue = vec![cfg.entry];
         let mut reached_exit_without_self_call = false;
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 751c9c3440f66..a3aa4af493aaf 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -679,7 +679,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         let sig = self.cx.tcx.erase_late_bound_regions(&sig);
 
         for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) {
-            self.check_type_for_ffi_and_report_errors(input_hir.ty.span, input_ty);
+            self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty);
         }
 
         if let hir::Return(ref ret_hir) = decl.output {
@@ -713,7 +713,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
             if nmod.abi != Abi::RustIntrinsic && nmod.abi != Abi::PlatformIntrinsic {
                 for ni in &nmod.items {
                     match ni.node {
-                        hir::ForeignItemFn(ref decl, _) => {
+                        hir::ForeignItemFn(ref decl, _, _) => {
                             vis.check_foreign_fn(ni.id, decl);
                         }
                         hir::ForeignItemStatic(ref ty, _) => {
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 429bfb8e3d606..b7ee688117d93 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -97,11 +97,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedMut {
     fn check_fn(&mut self,
                 cx: &LateContext,
                 _: FnKind,
-                decl: &hir::FnDecl,
-                _: &hir::Expr,
+                _: &hir::FnDecl,
+                body: &hir::Body,
                 _: Span,
                 _: ast::NodeId) {
-        for a in &decl.inputs {
+        for a in &body.arguments {
             self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat));
         }
     }
diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs
index 926c44824ce48..b27b164bd47aa 100644
--- a/src/librustc_metadata/astencode.rs
+++ b/src/librustc_metadata/astencode.rs
@@ -16,8 +16,7 @@ use cstore::CrateMetadata;
 use encoder::EncodeContext;
 use schema::*;
 
-use rustc::middle::cstore::{InlinedItem, InlinedItemRef};
-use rustc::middle::const_qualif::ConstQualif;
+use rustc::hir;
 use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, TyCtxt, Ty};
@@ -29,8 +28,10 @@ use rustc_serialize::Encodable;
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct Ast<'tcx> {
     id_range: IdRange,
-    item: Lazy<InlinedItem>,
+    body: Lazy<hir::Body>,
     side_tables: LazySeq<(ast::NodeId, TableEntry<'tcx>)>,
+    pub nested_bodies: LazySeq<hir::Body>,
+    pub rvalue_promotable_to_static: bool,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
@@ -39,16 +40,17 @@ enum TableEntry<'tcx> {
     NodeType(Ty<'tcx>),
     ItemSubsts(ty::ItemSubsts<'tcx>),
     Adjustment(ty::adjustment::Adjustment<'tcx>),
-    ConstQualif(ConstQualif),
 }
 
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
-    pub fn encode_inlined_item(&mut self, ii: InlinedItemRef<'tcx>) -> Lazy<Ast<'tcx>> {
+    pub fn encode_body(&mut self, body: hir::BodyId) -> Lazy<Ast<'tcx>> {
+        let body = self.tcx.map.body(body);
+
         let mut id_visitor = IdRangeComputingVisitor::new(&self.tcx.map);
-        ii.visit(&mut id_visitor);
+        id_visitor.visit_body(body);
 
-        let ii_pos = self.position();
-        ii.encode(self).unwrap();
+        let body_pos = self.position();
+        body.encode(self).unwrap();
 
         let tables_pos = self.position();
         let tables_count = {
@@ -56,14 +58,29 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 ecx: self,
                 count: 0,
             };
-            ii.visit(&mut visitor);
+            visitor.visit_body(body);
             visitor.count
         };
 
+        let nested_pos = self.position();
+        let nested_count = {
+            let mut visitor = NestedBodyEncodingVisitor {
+                ecx: self,
+                count: 0,
+            };
+            visitor.visit_body(body);
+            visitor.count
+        };
+
+        let rvalue_promotable_to_static =
+            self.tcx.rvalue_promotable_to_static.borrow()[&body.value.id];
+
         self.lazy(&Ast {
             id_range: id_visitor.result(),
-            item: Lazy::with_position(ii_pos),
+            body: Lazy::with_position(body_pos),
             side_tables: LazySeq::with_position_and_length(tables_pos, tables_count),
+            nested_bodies: LazySeq::with_position_and_length(nested_pos, nested_count),
+            rvalue_promotable_to_static: rvalue_promotable_to_static
         })
     }
 }
@@ -94,18 +111,36 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> {
         encode(tcx.tables().node_types.get(&id).cloned().map(TableEntry::NodeType));
         encode(tcx.tables().item_substs.get(&id).cloned().map(TableEntry::ItemSubsts));
         encode(tcx.tables().adjustments.get(&id).cloned().map(TableEntry::Adjustment));
-        encode(tcx.const_qualif_map.borrow().get(&id).cloned().map(TableEntry::ConstQualif));
     }
 }
 
-/// Decodes an item from its AST in the cdata's metadata and adds it to the
+struct NestedBodyEncodingVisitor<'a, 'b: 'a, 'tcx: 'b> {
+    ecx: &'a mut EncodeContext<'b, 'tcx>,
+    count: usize,
+}
+
+impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedBodyEncodingVisitor<'a, 'b, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_nested_body(&mut self, body: hir::BodyId) {
+        let body = self.ecx.tcx.map.body(body);
+        body.encode(self.ecx).unwrap();
+        self.count += 1;
+
+        self.visit_body(body);
+    }
+}
+
+/// Decodes an item's body from its AST in the cdata's metadata and adds it to the
 /// ast-map.
-pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata,
-                                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                     ast: Ast<'tcx>,
-                                     orig_did: DefId)
-                                     -> &'tcx InlinedItem {
-    debug!("> Decoding inlined fn: {:?}", tcx.item_path_str(orig_did));
+pub fn decode_body<'a, 'tcx>(cdata: &CrateMetadata,
+                             tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                             def_id: DefId,
+                             ast: Ast<'tcx>)
+                             -> &'tcx hir::Body {
+    debug!("> Decoding inlined fn: {}", tcx.item_path_str(def_id));
 
     let cnt = ast.id_range.max.as_usize() - ast.id_range.min.as_usize();
     let start = tcx.sess.reserve_node_ids(cnt);
@@ -115,12 +150,6 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata,
                          max: ast::NodeId::new(start.as_usize() + cnt),
                      }];
 
-    let ii = ast.item.decode((cdata, tcx, id_ranges));
-    let item_node_id = tcx.sess.next_node_id();
-    let ii = ast_map::map_decoded_item(&tcx.map,
-                                       ii,
-                                       item_node_id);
-
     for (id, entry) in ast.side_tables.decode((cdata, tcx, id_ranges)) {
         match entry {
             TableEntry::TypeRelativeDef(def) => {
@@ -135,11 +164,9 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata,
             TableEntry::Adjustment(adj) => {
                 tcx.tables.borrow_mut().adjustments.insert(id, adj);
             }
-            TableEntry::ConstQualif(qualif) => {
-                tcx.const_qualif_map.borrow_mut().insert(id, qualif);
-            }
         }
     }
 
-    ii
+    let body = ast.body.decode((cdata, tcx, id_ranges));
+    ast_map::map_decoded_body(&tcx.map, def_id, body, tcx.sess.next_node_id())
 }
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 7ec847d24cfa3..aab4034b7705a 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -88,13 +88,6 @@ pub struct CrateMetadata {
     pub dllimport_foreign_items: FxHashSet<DefIndex>,
 }
 
-pub struct CachedInlinedItem {
-    /// The NodeId of the RootInlinedParent HIR map entry
-    pub inlined_root: ast::NodeId,
-    /// The local NodeId of the inlined entity
-    pub item_id: ast::NodeId,
-}
-
 pub struct CStore {
     pub dep_graph: DepGraph,
     metas: RefCell<FxHashMap<CrateNum, Rc<CrateMetadata>>>,
@@ -104,8 +97,7 @@ pub struct CStore {
     used_link_args: RefCell<Vec<String>>,
     statically_included_foreign_items: RefCell<FxHashSet<DefIndex>>,
     pub dllimport_foreign_items: RefCell<FxHashSet<DefIndex>>,
-    pub inlined_item_cache: RefCell<DefIdMap<Option<CachedInlinedItem>>>,
-    pub defid_for_inlined_node: RefCell<NodeMap<DefId>>,
+    pub inlined_item_cache: RefCell<DefIdMap<Option<ast::NodeId>>>,
     pub visible_parent_map: RefCell<DefIdMap<DefId>>,
 }
 
@@ -121,7 +113,6 @@ impl CStore {
             dllimport_foreign_items: RefCell::new(FxHashSet()),
             visible_parent_map: RefCell::new(FxHashMap()),
             inlined_item_cache: RefCell::new(FxHashMap()),
-            defid_for_inlined_node: RefCell::new(FxHashMap()),
         }
     }
 
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 0ac3ffd5cb9ce..64513fa41b219 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -13,7 +13,7 @@ use encoder;
 use locator;
 use schema;
 
-use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, LibSource, DepKind, ExternCrate};
+use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, ExternCrate};
 use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro};
 use rustc::hir::def::{self, Def};
 use rustc::middle::lang_items;
@@ -36,6 +36,8 @@ use rustc::hir::svh::Svh;
 use rustc_back::target::Target;
 use rustc::hir;
 
+use std::collections::BTreeMap;
+
 impl<'tcx> CrateStore<'tcx> for cstore::CStore {
     fn describe_def(&self, def: DefId) -> Option<Def> {
         self.dep_graph.read(DepNode::MetaData(def));
@@ -128,7 +130,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
 
     fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>
     {
-        self.dep_graph.read(DepNode::MetaData(did));
+        // FIXME(#38501) We've skipped a `read` on the `HirBody` of
+        // a `fn` when encoding, so the dep-tracking wouldn't work.
+        // This is only used by rustdoc anyway, which shouldn't have
+        // incremental recompilation ever enabled.
+        assert!(!self.dep_graph.is_fully_enabled());
         self.get_crate_data(did.krate).get_fn_arg_names(did.index)
     }
 
@@ -423,94 +429,42 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         })
     }
 
-    fn maybe_get_item_ast<'a>(&'tcx self,
-                              tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                              def_id: DefId)
-                              -> Option<(&'tcx InlinedItem, ast::NodeId)>
+    fn maybe_get_item_body<'a>(&'tcx self,
+                               tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                               def_id: DefId)
+                               -> Option<&'tcx hir::Body>
     {
         self.dep_graph.read(DepNode::MetaData(def_id));
 
-        match self.inlined_item_cache.borrow().get(&def_id) {
-            Some(&None) => {
-                return None; // Not inlinable
-            }
-            Some(&Some(ref cached_inlined_item)) => {
+        if let Some(&cached) = self.inlined_item_cache.borrow().get(&def_id) {
+            return cached.map(|root_id| {
                 // Already inline
-                debug!("maybe_get_item_ast({}): already inline as node id {}",
-                          tcx.item_path_str(def_id), cached_inlined_item.item_id);
-                return Some((tcx.map.expect_inlined_item(cached_inlined_item.inlined_root),
-                             cached_inlined_item.item_id));
-            }
-            None => {
-                // Not seen yet
-            }
+                debug!("maybe_get_item_body({}): already inline", tcx.item_path_str(def_id));
+                tcx.map.expect_inlined_body(root_id)
+            });
         }
 
-        debug!("maybe_get_item_ast({}): inlining item", tcx.item_path_str(def_id));
+        debug!("maybe_get_item_body({}): inlining item", tcx.item_path_str(def_id));
 
-        let inlined = self.get_crate_data(def_id.krate).maybe_get_item_ast(tcx, def_id.index);
-
-        let cache_inlined_item = |original_def_id, inlined_item_id, inlined_root_node_id| {
-            let cache_entry = cstore::CachedInlinedItem {
-                inlined_root: inlined_root_node_id,
-                item_id: inlined_item_id,
-            };
-            self.inlined_item_cache
-                .borrow_mut()
-                .insert(original_def_id, Some(cache_entry));
-            self.defid_for_inlined_node
-                .borrow_mut()
-                .insert(inlined_item_id, original_def_id);
-        };
-
-        let find_inlined_item_root = |inlined_item_id| {
-            let mut node = inlined_item_id;
-
-            // If we can't find the inline root after a thousand hops, we can
-            // be pretty sure there's something wrong with the HIR map.
-            for _ in 0 .. 1000 {
-                let parent_node = tcx.map.get_parent_node(node);
-                if parent_node == node {
-                    return node;
-                }
-                node = parent_node;
-            }
-            bug!("cycle in HIR map parent chain")
-        };
+        let inlined = self.get_crate_data(def_id.krate).maybe_get_item_body(tcx, def_id.index);
 
-        match inlined {
-            None => {
-                self.inlined_item_cache
-                    .borrow_mut()
-                    .insert(def_id, None);
-            }
-            Some(&InlinedItem { ref body, .. }) => {
-                let inlined_root_node_id = find_inlined_item_root(body.id);
-                cache_inlined_item(def_id, inlined_root_node_id, inlined_root_node_id);
-            }
-        }
+        self.inlined_item_cache.borrow_mut().insert(def_id, inlined.map(|body| {
+            let root_id = tcx.map.get_parent_node(body.value.id);
+            assert_eq!(tcx.map.get_parent_node(root_id), root_id);
+            root_id
+        }));
 
-        // We can be sure to hit the cache now
-        return self.maybe_get_item_ast(tcx, def_id);
+        inlined
     }
 
-    fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId> {
-        assert!(!def_id.is_local());
-        match self.inlined_item_cache.borrow().get(&def_id) {
-            Some(&Some(ref cached_inlined_item)) => {
-                Some(cached_inlined_item.item_id)
-            }
-            Some(&None) => {
-                None
-            }
-            _ => {
-                bug!("Trying to lookup inlined NodeId for unexpected item");
-            }
-        }
+    fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
+        self.dep_graph.read(DepNode::MetaData(def));
+        self.get_crate_data(def.krate).item_body_nested_bodies(def.index)
     }
 
-    fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId> {
-        self.defid_for_inlined_node.borrow().get(&node_id).map(|x| *x)
+    fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool {
+        self.dep_graph.read(DepNode::MetaData(def));
+        self.get_crate_data(def.krate).const_is_rvalue_promotable_to_static(def.index)
     }
 
     fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx> {
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 400a3ac0e3e0d..c27e06c50222b 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -10,7 +10,7 @@
 
 // Decoding metadata from a single crate's metadata
 
-use astencode::decode_inlined_item;
+use astencode::decode_body;
 use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary};
 use schema::*;
 
@@ -18,7 +18,7 @@ use rustc::hir::map::{DefKey, DefPath, DefPathData};
 use rustc::hir;
 use rustc::hir::intravisit::IdRange;
 
-use rustc::middle::cstore::{InlinedItem, LinkagePreference};
+use rustc::middle::cstore::LinkagePreference;
 use rustc::hir::def::{self, Def, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc::middle::lang_items;
@@ -32,6 +32,7 @@ use rustc::mir::Mir;
 
 use std::borrow::Cow;
 use std::cell::Ref;
+use std::collections::BTreeMap;
 use std::io;
 use std::mem;
 use std::str;
@@ -819,20 +820,27 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn maybe_get_item_ast(&self,
-                              tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                              id: DefIndex)
-                              -> Option<&'tcx InlinedItem> {
-        debug!("Looking up item: {:?}", id);
+    pub fn maybe_get_item_body(&self,
+                               tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                               id: DefIndex)
+                               -> Option<&'tcx hir::Body> {
         if self.is_proc_macro(id) { return None; }
-        let item_doc = self.entry(id);
-        let item_did = self.local_def_id(id);
-        item_doc.ast.map(|ast| {
-            let ast = ast.decode(self);
-            decode_inlined_item(self, tcx, ast, item_did)
+        self.entry(id).ast.map(|ast| {
+            decode_body(self, tcx, self.local_def_id(id), ast.decode(self))
         })
     }
 
+    pub fn item_body_nested_bodies(&self, id: DefIndex) -> BTreeMap<hir::BodyId, hir::Body> {
+        self.entry(id).ast.into_iter().flat_map(|ast| {
+            ast.decode(self).nested_bodies.decode(self).map(|body| (body.id(), body))
+        }).collect()
+    }
+
+    pub fn const_is_rvalue_promotable_to_static(&self, id: DefIndex) -> bool {
+        self.entry(id).ast.expect("const item missing `ast`")
+            .decode(self).rvalue_promotable_to_static
+    }
+
     pub fn is_item_mir_available(&self, id: DefIndex) -> bool {
         !self.is_proc_macro(id) &&
         self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some()
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index bc0a64b9a5170..72dcb4ba9a3a8 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -12,8 +12,7 @@ use cstore;
 use index::Index;
 use schema::*;
 
-use rustc::middle::cstore::{InlinedItemRef, LinkMeta};
-use rustc::middle::cstore::{LinkagePreference, NativeLibrary};
+use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary};
 use rustc::hir::def;
 use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId};
 use rustc::hir::map::definitions::DefPathTable;
@@ -34,6 +33,7 @@ use std::io::Cursor;
 use std::rc::Rc;
 use std::u32;
 use syntax::ast::{self, CRATE_NODE_ID};
+use syntax::codemap::Spanned;
 use syntax::attr;
 use syntax::symbol::Symbol;
 use syntax_pos;
@@ -442,10 +442,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let kind = match trait_item.kind {
             ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
             ty::AssociatedKind::Method => {
-                let fn_data = if let hir::MethodTraitItem(ref sig, _) = ast_item.node {
+                let fn_data = if let hir::TraitItemKind::Method(_, ref m) = ast_item.node {
+                    let arg_names = match *m {
+                        hir::TraitMethod::Required(ref names) => {
+                            self.encode_fn_arg_names(names)
+                        }
+                        hir::TraitMethod::Provided(body) => {
+                            self.encode_fn_arg_names_for_body(body)
+                        }
+                    };
                     FnData {
                         constness: hir::Constness::NotConst,
-                        arg_names: self.encode_fn_arg_names(&sig.decl),
+                        arg_names: arg_names
                     }
                 } else {
                     bug!()
@@ -486,13 +494,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             generics: Some(self.encode_generics(def_id)),
             predicates: Some(self.encode_predicates(def_id)),
 
-            ast: if let hir::ConstTraitItem(_, Some(_)) = ast_item.node {
-                // We only save the HIR for associated consts with bodies
-                // (InlinedItemRef::from_trait_item panics otherwise)
-                let trait_def_id = trait_item.container.id();
-                Some(self.encode_inlined_item(
-                    InlinedItemRef::from_trait_item(trait_def_id, ast_item, tcx)
-                ))
+            ast: if let hir::TraitItemKind::Const(_, Some(body)) = ast_item.node {
+                Some(self.encode_body(body))
             } else {
                 None
             },
@@ -501,12 +504,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 
     fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
-        let tcx = self.tcx;
-
         let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
         let ast_item = self.tcx.map.expect_impl_item(node_id);
         let impl_item = self.tcx.associated_item(def_id);
-        let impl_def_id = impl_item.container.id();
 
         let container = match impl_item.defaultness {
             hir::Defaultness::Default { has_value: true } => AssociatedContainer::ImplDefault,
@@ -518,10 +518,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let kind = match impl_item.kind {
             ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
             ty::AssociatedKind::Method => {
-                let fn_data = if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
+                let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
                     FnData {
                         constness: sig.constness,
-                        arg_names: self.encode_fn_arg_names(&sig.decl),
+                        arg_names: self.encode_fn_arg_names_for_body(body),
                     }
                 } else {
                     bug!()
@@ -535,17 +535,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             ty::AssociatedKind::Type => EntryKind::AssociatedType(container)
         };
 
-        let (ast, mir) = if impl_item.kind == ty::AssociatedKind::Const {
-            (true, true)
-        } else if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
+        let (ast, mir) = if let hir::ImplItemKind::Const(_, body) = ast_item.node {
+            (Some(body), true)
+        } else if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
             let generics = self.tcx.item_generics(def_id);
             let types = generics.parent_types as usize + generics.types.len();
             let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs);
             let is_const_fn = sig.constness == hir::Constness::Const;
+            let ast = if is_const_fn { Some(body) } else { None };
             let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
-            (is_const_fn, needs_inline || is_const_fn || always_encode_mir)
+            (ast, needs_inline || is_const_fn || always_encode_mir)
         } else {
-            (false, false)
+            (None, false)
         };
 
         Entry {
@@ -563,27 +564,28 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             generics: Some(self.encode_generics(def_id)),
             predicates: Some(self.encode_predicates(def_id)),
 
-            ast: if ast {
-                Some(self.encode_inlined_item(
-                    InlinedItemRef::from_impl_item(impl_def_id, ast_item, tcx)
-                ))
-            } else {
-                None
-            },
+            ast: ast.map(|body| self.encode_body(body)),
             mir: if mir { self.encode_mir(def_id) } else { None },
         }
     }
 
-    fn encode_fn_arg_names(&mut self, decl: &hir::FnDecl) -> LazySeq<ast::Name> {
-        self.lazy_seq(decl.inputs.iter().map(|arg| {
-            if let PatKind::Binding(_, _, ref path1, _) = arg.pat.node {
-                path1.node
-            } else {
-                Symbol::intern("")
+    fn encode_fn_arg_names_for_body(&mut self, body_id: hir::BodyId)
+                                    -> LazySeq<ast::Name> {
+        let _ignore = self.tcx.dep_graph.in_ignore();
+        let body = self.tcx.map.body(body_id);
+        self.lazy_seq(body.arguments.iter().map(|arg| {
+            match arg.pat.node {
+                PatKind::Binding(_, _, name, _) => name.node,
+                _ => Symbol::intern("")
             }
         }))
     }
 
+    fn encode_fn_arg_names(&mut self, names: &[Spanned<ast::Name>])
+                           -> LazySeq<ast::Name> {
+        self.lazy_seq(names.iter().map(|name| name.node))
+    }
+
     fn encode_mir(&mut self, def_id: DefId) -> Option<Lazy<mir::Mir<'tcx>>> {
         self.tcx.mir_map.borrow().get(&def_id).map(|mir| self.lazy(&*mir.borrow()))
     }
@@ -619,10 +621,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic,
             hir::ItemStatic(_, hir::MutImmutable, _) => EntryKind::ImmStatic,
             hir::ItemConst(..) => EntryKind::Const,
-            hir::ItemFn(ref decl, _, constness, ..) => {
+            hir::ItemFn(_, _, constness, .., body) => {
                 let data = FnData {
                     constness: constness,
-                    arg_names: self.encode_fn_arg_names(&decl),
+                    arg_names: self.encode_fn_arg_names_for_body(body),
                 };
 
                 EntryKind::Fn(self.lazy(&data))
@@ -793,16 +795,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             },
 
             ast: match item.node {
-                hir::ItemConst(..) |
-                hir::ItemFn(_, _, hir::Constness::Const, ..) => {
-                    Some(self.encode_inlined_item(
-                        InlinedItemRef::from_item(def_id, item, tcx)
-                    ))
+                hir::ItemConst(_, body) |
+                hir::ItemFn(_, _, hir::Constness::Const, _, _, body) => {
+                    Some(self.encode_body(body))
                 }
                 _ => None,
             },
             mir: match item.node {
-                hir::ItemStatic(..) |
+                hir::ItemStatic(..) if self.tcx.sess.opts.debugging_opts.always_encode_mir => {
+                    self.encode_mir(def_id)
+                }
                 hir::ItemConst(..) => self.encode_mir(def_id),
                 hir::ItemFn(_, _, constness, _, ref generics, _) => {
                     let tps_len = generics.ty_params.len();
@@ -913,10 +915,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         debug!("writing foreign item {}", tcx.node_path_str(nitem.id));
 
         let kind = match nitem.node {
-            hir::ForeignItemFn(ref fndecl, _) => {
+            hir::ForeignItemFn(_, ref names, _) => {
                 let data = FnData {
                     constness: hir::Constness::NotConst,
-                    arg_names: self.encode_fn_arg_names(&fndecl),
+                    arg_names: self.encode_fn_arg_names(names),
                 };
                 EntryKind::ForeignFn(self.lazy(&data))
             }
@@ -1162,6 +1164,8 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'a, 'tcx> {
         }
     }
 
+    fn visit_trait_item(&mut self, _trait_item: &'v hir::TraitItem) {}
+
     fn visit_impl_item(&mut self, _impl_item: &'v hir::ImplItem) {
         // handled in `visit_item` above
     }
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index e06d940de7e58..63bb1bf20c06c 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -729,7 +729,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             name: Some(name),
             source_info: Some(source_info),
         });
-        let extent = self.extent_of_innermost_scope();
+        let extent = self.hir.tcx().region_maps.var_scope(var_id);
         self.schedule_drop(source_info.span, extent, &Lvalue::Local(var), var_ty);
         self.var_indices.insert(var_id, var);
 
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 0e4dbb0477716..cfdc1bf27df35 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -126,7 +126,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
                                        arguments: A,
                                        abi: Abi,
                                        return_ty: Ty<'gcx>,
-                                       ast_body: &'gcx hir::Expr)
+                                       body: &'gcx hir::Body)
                                        -> Mir<'tcx>
     where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
 {
@@ -136,17 +136,16 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
     let span = tcx.map.span(fn_id);
     let mut builder = Builder::new(hir, span, arguments.len(), return_ty);
 
-    let body_id = ast_body.id;
     let call_site_extent =
         tcx.region_maps.lookup_code_extent(
-            CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id });
+            CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body.value.id });
     let arg_extent =
         tcx.region_maps.lookup_code_extent(
-            CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
+            CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.value.id });
     let mut block = START_BLOCK;
     unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
         unpack!(block = builder.in_scope(arg_extent, block, |builder| {
-            builder.args_and_body(block, &arguments, arg_extent, ast_body)
+            builder.args_and_body(block, &arguments, arg_extent, &body.value)
         }));
         // Attribute epilogue to function's closing brace
         let fn_end = Span { lo: span.hi, ..span };
@@ -197,9 +196,10 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
 
 pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
                                        item_id: ast::NodeId,
-                                       ast_expr: &'tcx hir::Expr)
+                                       body_id: hir::BodyId)
                                        -> Mir<'tcx> {
     let tcx = hir.tcx();
+    let ast_expr = &tcx.map.body(body_id).value;
     let ty = tcx.tables().expr_ty_adjusted(ast_expr);
     let span = tcx.map.span(item_id);
     let mut builder = Builder::new(hir, span, 0, ty);
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index c02a1822d7369..59a11782e0856 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -253,7 +253,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                             f: F)
         where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>)
     {
-        let extent = self.extent_of_innermost_scope();
+        let extent = self.scopes.last().map(|scope| scope.extent).unwrap();
         let loop_scope = LoopScope {
             extent: extent.clone(),
             continue_block: loop_block,
@@ -411,10 +411,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn extent_of_innermost_scope(&self) -> CodeExtent {
-        self.scopes.last().map(|scope| scope.extent).unwrap()
-    }
-
     /// Returns the extent of the scope which should be exited by a
     /// return.
     pub fn extent_of_return_scope(&self) -> CodeExtent {
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index d579cdb042fb3..cc65fdede092f 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -575,7 +575,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         }
 
         // Now comes the rote stuff:
-        hir::ExprRepeat(ref v, ref c) => {
+        hir::ExprRepeat(ref v, c) => {
+            let c = &cx.tcx.map.body(c).value;
             ExprKind::Repeat {
                 value: v.to_ref(),
                 count: TypedConstVal {
@@ -585,7 +586,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         ConstVal::Integral(ConstInt::Usize(u)) => u,
                         other => bug!("constant evaluation of repeat count yielded {:?}", other),
                     },
-                },
+                }
             }
         }
         hir::ExprRet(ref v) => ExprKind::Return { value: v.to_ref() },
@@ -780,7 +781,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             let body_id = match cx.tcx.map.find(closure_expr_id) {
                 Some(map::NodeExpr(expr)) => {
                     match expr.node {
-                        hir::ExprClosure(.., body_id, _) => body_id.node_id(),
+                        hir::ExprClosure(.., body, _) => body.node_id,
                         _ => {
                             span_bug!(expr.span, "closure expr is not a closure expr");
                         }
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index e2a516edbc835..cbc53ea3c51c7 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -129,16 +129,17 @@ impl<'a, 'gcx, 'tcx> CxBuilder<'a, 'gcx, 'tcx> {
 }
 
 impl<'a, 'gcx> BuildMir<'a, 'gcx> {
-    fn build_const_integer(&mut self, expr: &'gcx hir::Expr) {
+    fn build_const_integer(&mut self, body: hir::BodyId) {
+        let body = self.tcx.map.body(body);
         // FIXME(eddyb) Closures should have separate
         // function definition IDs and expression IDs.
         // Type-checking should not let closures get
         // this far in an integer constant position.
-        if let hir::ExprClosure(..) = expr.node {
+        if let hir::ExprClosure(..) = body.value.node {
             return;
         }
-        self.cx(MirSource::Const(expr.id)).build(|cx| {
-            build::construct_const(cx, expr.id, expr)
+        self.cx(MirSource::Const(body.value.id)).build(|cx| {
+            build::construct_const(cx, body.value.id, body.id())
         });
     }
 }
@@ -151,12 +152,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
     // Const and static items.
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         match item.node {
-            hir::ItemConst(_, ref expr) => {
+            hir::ItemConst(_, expr) => {
                 self.cx(MirSource::Const(item.id)).build(|cx| {
                     build::construct_const(cx, item.id, expr)
                 });
             }
-            hir::ItemStatic(_, m, ref expr) => {
+            hir::ItemStatic(_, m, expr) => {
                 self.cx(MirSource::Static(item.id, m)).build(|cx| {
                     build::construct_const(cx, item.id, expr)
                 });
@@ -168,7 +169,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
 
     // Trait associated const defaults.
     fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
-        if let hir::ConstTraitItem(_, Some(ref expr)) = item.node {
+        if let hir::TraitItemKind::Const(_, Some(expr)) = item.node {
             self.cx(MirSource::Const(item.id)).build(|cx| {
                 build::construct_const(cx, item.id, expr)
             });
@@ -178,7 +179,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
 
     // Impl associated const.
     fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
-        if let hir::ImplItemKind::Const(_, ref expr) = item.node {
+        if let hir::ImplItemKind::Const(_, expr) = item.node {
             self.cx(MirSource::Const(item.id)).build(|cx| {
                 build::construct_const(cx, item.id, expr)
             });
@@ -188,7 +189,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
 
     // Repeat counts, i.e. [expr; constant].
     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
-        if let hir::ExprRepeat(_, ref count) = expr.node {
+        if let hir::ExprRepeat(_, count) = expr.node {
             self.build_const_integer(count);
         }
         intravisit::walk_expr(self, expr);
@@ -196,7 +197,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
 
     // Array lengths, i.e. [T; constant].
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-        if let hir::TyArray(_, ref length) = ty.node {
+        if let hir::TyArray(_, length) = ty.node {
             self.build_const_integer(length);
         }
         intravisit::walk_ty(self, ty);
@@ -205,7 +206,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
     // Enum variant discriminant values.
     fn visit_variant(&mut self, v: &'tcx hir::Variant,
                      g: &'tcx hir::Generics, item_id: ast::NodeId) {
-        if let Some(ref expr) = v.node.disr_expr {
+        if let Some(expr) = v.node.disr_expr {
             self.build_const_integer(expr);
         }
         intravisit::walk_variant(self, v, g, item_id);
@@ -214,7 +215,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
     fn visit_fn(&mut self,
                 fk: FnKind<'tcx>,
                 decl: &'tcx hir::FnDecl,
-                body_id: hir::ExprId,
+                body_id: hir::BodyId,
                 span: Span,
                 id: ast::NodeId) {
         // fetch the fully liberated fn signature (that is, all bound
@@ -227,22 +228,21 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
         };
 
         let (abi, implicit_argument) = if let FnKind::Closure(..) = fk {
-            (Abi::Rust, Some((closure_self_ty(self.tcx, id, body_id.node_id()), None)))
+            (Abi::Rust, Some((closure_self_ty(self.tcx, id, body_id.node_id), None)))
         } else {
             let def_id = self.tcx.map.local_def_id(id);
             (self.tcx.item_type(def_id).fn_abi(), None)
         };
 
+        let body = self.tcx.map.body(body_id);
         let explicit_arguments =
-            decl.inputs
+            body.arguments
                 .iter()
                 .enumerate()
                 .map(|(index, arg)| {
                     (fn_sig.inputs()[index], Some(&*arg.pat))
                 });
 
-        let body = self.tcx.map.expr(body_id);
-
         let arguments = implicit_argument.into_iter().chain(explicit_arguments);
         self.cx(MirSource::Fn(id)).build(|cx| {
             build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body)
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 86f56d0035841..d1d9a201567bb 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -26,8 +26,8 @@
 
 use rustc::dep_graph::DepNode;
 use rustc::ty::cast::CastKind;
-use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, compare_lit_exprs};
-use rustc_const_eval::{ConstFnNode, eval_const_expr_partial, lookup_const_by_id};
+use rustc_const_eval::{ConstEvalErr, compare_lit_exprs};
+use rustc_const_eval::{eval_const_expr_partial};
 use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math};
 use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
 use rustc_const_eval::ErrKind::UnresolvedPath;
@@ -35,80 +35,36 @@ use rustc_const_eval::EvalHint::ExprTypeChecked;
 use rustc_const_math::{ConstMathErr, Op};
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
+use rustc::hir::map::blocks::FnLikeNode;
 use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::mem_categorization as mc;
 use rustc::middle::mem_categorization::Categorization;
+use rustc::mir::transform::MirSource;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::traits::Reveal;
 use rustc::util::common::ErrorReported;
-use rustc::util::nodemap::NodeMap;
-use rustc::middle::const_qualif::ConstQualif;
+use rustc::util::nodemap::NodeSet;
 use rustc::lint::builtin::CONST_ERR;
 
 use rustc::hir::{self, PatKind};
 use syntax::ast;
 use syntax_pos::Span;
-use rustc::hir::intravisit::{self, FnKind, Visitor, NestedVisitorMap};
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 
 use std::collections::hash_map::Entry;
 use std::cmp::Ordering;
-
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-enum Mode {
-    Const,
-    ConstFn,
-    Static,
-    StaticMut,
-
-    // An expression that occurs outside of any constant context
-    // (i.e. `const`, `static`, array lengths, etc.). The value
-    // can be variable at runtime, but will be promotable to
-    // static memory if we can prove it is actually constant.
-    Var,
-}
+use std::mem;
 
 struct CheckCrateVisitor<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    mode: Mode,
-    qualif: ConstQualif,
-    rvalue_borrows: NodeMap<hir::Mutability>,
+    in_fn: bool,
+    promotable: bool,
+    mut_rvalue_borrows: NodeSet,
+    param_env: ty::ParameterEnvironment<'tcx>,
 }
 
 impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
-    fn with_mode<F, R>(&mut self, mode: Mode, f: F) -> R
-        where F: FnOnce(&mut CheckCrateVisitor<'a, 'gcx>) -> R
-    {
-        let (old_mode, old_qualif) = (self.mode, self.qualif);
-        self.mode = mode;
-        self.qualif = ConstQualif::empty();
-        let r = f(self);
-        self.mode = old_mode;
-        self.qualif = old_qualif;
-        r
-    }
-
-    fn with_euv<F, R>(&mut self, item_id: Option<ast::NodeId>, f: F) -> R
-        where F: for<'b, 'tcx> FnOnce(&mut euv::ExprUseVisitor<'b, 'gcx, 'tcx>) -> R
-    {
-        let param_env = match item_id {
-            Some(item_id) => ty::ParameterEnvironment::for_item(self.tcx, item_id),
-            None => self.tcx.empty_parameter_environment(),
-        };
-
-        self.tcx
-            .infer_ctxt(None, Some(param_env), Reveal::NotSpecializable)
-            .enter(|infcx| f(&mut euv::ExprUseVisitor::new(self, &infcx)))
-    }
-
-    fn global_expr(&mut self, mode: Mode, expr: &'gcx hir::Expr) -> ConstQualif {
-        assert!(mode != Mode::Var);
-        match self.tcx.const_qualif_map.borrow_mut().entry(expr.id) {
-            Entry::Occupied(entry) => return *entry.get(),
-            Entry::Vacant(entry) => {
-                // Prevent infinite recursion on re-entry.
-                entry.insert(ConstQualif::empty());
-            }
-        }
+    fn check_const_eval(&self, expr: &'gcx hir::Expr) {
         if let Err(err) = eval_const_expr_partial(self.tcx, expr, ExprTypeChecked, None) {
             match err.kind {
                 UnimplementedConstVal(_) => {}
@@ -124,184 +80,78 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
                 }
             }
         }
-        self.with_mode(mode, |this| {
-            this.with_euv(None, |euv| euv.consume_expr(expr));
-            this.visit_expr(expr);
-            this.qualif
-        })
     }
 
-    fn fn_like(&mut self,
-               fk: FnKind<'gcx>,
-               fd: &'gcx hir::FnDecl,
-               b: hir::ExprId,
-               s: Span,
-               fn_id: ast::NodeId)
-               -> ConstQualif {
-        match self.tcx.const_qualif_map.borrow_mut().entry(fn_id) {
-            Entry::Occupied(entry) => return *entry.get(),
-            Entry::Vacant(entry) => {
-                // Prevent infinite recursion on re-entry.
-                entry.insert(ConstQualif::empty());
-            }
+    // Adds the worst effect out of all the values of one type.
+    fn add_type(&mut self, ty: Ty<'gcx>) {
+        if ty.type_contents(self.tcx).interior_unsafe() {
+            self.promotable = false;
         }
 
-        let mode = match fk {
-            FnKind::ItemFn(_, _, _, hir::Constness::Const, ..)
-                => Mode::ConstFn,
-            FnKind::Method(_, m, ..) => {
-                if m.constness == hir::Constness::Const {
-                    Mode::ConstFn
-                } else {
-                    Mode::Var
-                }
-            }
-            _ => Mode::Var,
-        };
-
-        let qualif = self.with_mode(mode, |this| {
-            let body = this.tcx.map.expr(b);
-            this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, body));
-            intravisit::walk_fn(this, fk, fd, b, s, fn_id);
-            this.qualif
-        });
-
-        // Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
-        // and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
-        let qualif = qualif & (ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
-
-        self.tcx.const_qualif_map.borrow_mut().insert(fn_id, qualif);
-        qualif
-    }
-
-    fn add_qualif(&mut self, qualif: ConstQualif) {
-        self.qualif = self.qualif | qualif;
-    }
-
-    /// Returns true if the call is to a const fn or method.
-    fn handle_const_fn_call(&mut self, _expr: &hir::Expr, def_id: DefId, ret_ty: Ty<'gcx>) -> bool {
-        match lookup_const_fn_by_id(self.tcx, def_id) {
-            Some(ConstFnNode::Local(fn_like)) => {
-                let qualif = self.fn_like(fn_like.kind(),
-                                          fn_like.decl(),
-                                          fn_like.body(),
-                                          fn_like.span(),
-                                          fn_like.id());
-
-                self.add_qualif(qualif);
-
-                if ret_ty.type_contents(self.tcx).interior_unsafe() {
-                    self.add_qualif(ConstQualif::MUTABLE_MEM);
-                }
-
-                true
-            },
-            Some(ConstFnNode::Inlined(ii)) => {
-                let node_id = ii.body.id;
-
-                let qualif = match self.tcx.const_qualif_map.borrow_mut().entry(node_id) {
-                    Entry::Occupied(entry) => *entry.get(),
-                    _ => bug!("const qualif entry missing for inlined item")
-                };
-
-                self.add_qualif(qualif);
-
-                if ret_ty.type_contents(self.tcx).interior_unsafe() {
-                    self.add_qualif(ConstQualif::MUTABLE_MEM);
-                }
-
-                true
-            },
-            None => false
+        if self.tcx.type_needs_drop_given_env(ty, &self.param_env) {
+            self.promotable = false;
         }
     }
 
-    fn record_borrow(&mut self, id: ast::NodeId, mutbl: hir::Mutability) {
-        match self.rvalue_borrows.entry(id) {
-            Entry::Occupied(mut entry) => {
-                // Merge the two borrows, taking the most demanding
-                // one, mutability-wise.
-                if mutbl == hir::MutMutable {
-                    entry.insert(mutbl);
-                }
-            }
-            Entry::Vacant(entry) => {
-                entry.insert(mutbl);
-            }
-        }
+    fn handle_const_fn_call(&mut self, def_id: DefId, ret_ty: Ty<'gcx>) {
+        self.add_type(ret_ty);
+
+        self.promotable &= if let Some(fn_id) = self.tcx.map.as_local_node_id(def_id) {
+            FnLikeNode::from_node(self.tcx.map.get(fn_id)).map_or(false, |fn_like| {
+                fn_like.constness() == hir::Constness::Const
+            })
+        } else {
+            self.tcx.sess.cstore.is_const_fn(def_id)
+        };
     }
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+        NestedVisitorMap::None
     }
 
-    fn visit_item(&mut self, i: &'tcx hir::Item) {
-        debug!("visit_item(item={})", self.tcx.map.node_to_string(i.id));
-        assert_eq!(self.mode, Mode::Var);
-        match i.node {
-            hir::ItemStatic(_, hir::MutImmutable, ref expr) => {
-                self.global_expr(Mode::Static, &expr);
-            }
-            hir::ItemStatic(_, hir::MutMutable, ref expr) => {
-                self.global_expr(Mode::StaticMut, &expr);
-            }
-            hir::ItemConst(_, ref expr) => {
-                self.global_expr(Mode::Const, &expr);
-            }
-            hir::ItemEnum(ref enum_definition, _) => {
-                for var in &enum_definition.variants {
-                    if let Some(ref ex) = var.node.disr_expr {
-                        self.global_expr(Mode::Const, &ex);
-                    }
-                }
-            }
-            _ => {
-                intravisit::walk_item(self, i);
+    fn visit_nested_body(&mut self, body: hir::BodyId) {
+        match self.tcx.rvalue_promotable_to_static.borrow_mut().entry(body.node_id) {
+            Entry::Occupied(_) => return,
+            Entry::Vacant(entry) => {
+                // Prevent infinite recursion on re-entry.
+                entry.insert(false);
             }
         }
-    }
 
-    fn visit_trait_item(&mut self, t: &'tcx hir::TraitItem) {
-        match t.node {
-            hir::ConstTraitItem(_, ref default) => {
-                if let Some(ref expr) = *default {
-                    self.global_expr(Mode::Const, &expr);
-                } else {
-                    intravisit::walk_trait_item(self, t);
-                }
-            }
-            _ => self.with_mode(Mode::Var, |v| intravisit::walk_trait_item(v, t)),
-        }
-    }
+        let item_id = self.tcx.map.body_owner(body);
 
-    fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) {
-        match i.node {
-            hir::ImplItemKind::Const(_, ref expr) => {
-                self.global_expr(Mode::Const, &expr);
-            }
-            _ => self.with_mode(Mode::Var, |v| intravisit::walk_impl_item(v, i)),
+        let outer_in_fn = self.in_fn;
+        self.in_fn = match MirSource::from_node(self.tcx, item_id) {
+            MirSource::Fn(_) => true,
+            _ => false
+        };
+
+        let body = self.tcx.map.body(body);
+        if !self.in_fn {
+            self.check_const_eval(&body.value);
         }
-    }
 
-    fn visit_fn(&mut self,
-                fk: FnKind<'tcx>,
-                fd: &'tcx hir::FnDecl,
-                b: hir::ExprId,
-                s: Span,
-                fn_id: ast::NodeId) {
-        self.fn_like(fk, fd, b, s, fn_id);
+        let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
+        let outer_param_env = mem::replace(&mut self.param_env, param_env);
+        self.tcx.infer_ctxt(None, Some(self.param_env.clone()), Reveal::NotSpecializable)
+            .enter(|infcx| euv::ExprUseVisitor::new(self, &infcx).consume_body(body));
+
+        self.visit_body(body);
+
+        self.param_env = outer_param_env;
+        self.in_fn = outer_in_fn;
     }
 
     fn visit_pat(&mut self, p: &'tcx hir::Pat) {
         match p.node {
             PatKind::Lit(ref lit) => {
-                self.global_expr(Mode::Const, &lit);
+                self.check_const_eval(lit);
             }
             PatKind::Range(ref start, ref end) => {
-                self.global_expr(Mode::Const, &start);
-                self.global_expr(Mode::Const, &end);
+                self.check_const_eval(start);
+                self.check_const_eval(end);
 
                 match compare_lit_exprs(self.tcx, p.span, start, end) {
                     Ok(Ordering::Less) |
@@ -315,119 +165,60 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
                     Err(ErrorReported) => {}
                 }
             }
-            _ => intravisit::walk_pat(self, p),
+            _ => {}
         }
+        intravisit::walk_pat(self, p);
     }
 
-    fn visit_block(&mut self, block: &'tcx hir::Block) {
-        // Check all statements in the block
-        for stmt in &block.stmts {
-            match stmt.node {
-                hir::StmtDecl(ref decl, _) => {
-                    match decl.node {
-                        hir::DeclLocal(_) => {}
-                        // Item statements are allowed
-                        hir::DeclItem(_) => continue,
+    fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt) {
+        match stmt.node {
+            hir::StmtDecl(ref decl, _) => {
+                match decl.node {
+                    hir::DeclLocal(_) => {
+                        self.promotable = false;
                     }
+                    // Item statements are allowed
+                    hir::DeclItem(_) => {}
                 }
-                hir::StmtExpr(..) => {}
-                hir::StmtSemi(..) => {}
             }
-            self.add_qualif(ConstQualif::NOT_CONST);
+            hir::StmtExpr(..) |
+            hir::StmtSemi(..) => {
+                self.promotable = false;
+            }
         }
-        intravisit::walk_block(self, block);
+        intravisit::walk_stmt(self, stmt);
     }
 
     fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
-        let mut outer = self.qualif;
-        self.qualif = ConstQualif::empty();
+        let outer = self.promotable;
+        self.promotable = true;
 
         let node_ty = self.tcx.tables().node_id_to_type(ex.id);
         check_expr(self, ex, node_ty);
         check_adjustments(self, ex);
 
-        // Special-case some expressions to avoid certain flags bubbling up.
-        match ex.node {
-            hir::ExprCall(ref callee, ref args) => {
-                for arg in args {
-                    self.visit_expr(&arg)
+        if let hir::ExprMatch(ref discr, ref arms, _) = ex.node {
+            // Compute the most demanding borrow from all the arms'
+            // patterns and set that on the discriminator.
+            let mut mut_borrow = false;
+            for pat in arms.iter().flat_map(|arm| &arm.pats) {
+                if self.mut_rvalue_borrows.remove(&pat.id) {
+                    mut_borrow = true;
                 }
-
-                let inner = self.qualif;
-                self.visit_expr(&callee);
-                // The callee's size doesn't count in the call.
-                let added = self.qualif - inner;
-                self.qualif = inner | (added - ConstQualif::NON_ZERO_SIZED);
             }
-            hir::ExprRepeat(ref element, _) => {
-                self.visit_expr(&element);
-                // The count is checked elsewhere (typeck).
-                let count = match node_ty.sty {
-                    ty::TyArray(_, n) => n,
-                    _ => bug!(),
-                };
-                // [element; 0] is always zero-sized.
-                if count == 0 {
-                    self.qualif.remove(ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
-                }
+            if mut_borrow {
+                self.mut_rvalue_borrows.insert(discr.id);
             }
-            hir::ExprMatch(ref discr, ref arms, _) => {
-                // Compute the most demanding borrow from all the arms'
-                // patterns and set that on the discriminator.
-                let mut borrow = None;
-                for pat in arms.iter().flat_map(|arm| &arm.pats) {
-                    let pat_borrow = self.rvalue_borrows.remove(&pat.id);
-                    match (borrow, pat_borrow) {
-                        (None, _) |
-                        (_, Some(hir::MutMutable)) => {
-                            borrow = pat_borrow;
-                        }
-                        _ => {}
-                    }
-                }
-                if let Some(mutbl) = borrow {
-                    self.record_borrow(discr.id, mutbl);
-                }
-                intravisit::walk_expr(self, ex);
-            }
-            _ => intravisit::walk_expr(self, ex),
         }
 
+        intravisit::walk_expr(self, ex);
+
         // Handle borrows on (or inside the autorefs of) this expression.
-        match self.rvalue_borrows.remove(&ex.id) {
-            Some(hir::MutImmutable) => {
-                // Constants cannot be borrowed if they contain interior mutability as
-                // it means that our "silent insertion of statics" could change
-                // initializer values (very bad).
-                // If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has
-                // propagated from another error, so erroring again would be just noise.
-                let tc = node_ty.type_contents(self.tcx);
-                if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && tc.interior_unsafe() {
-                    outer = outer | ConstQualif::NOT_CONST;
-                }
-                // If the reference has to be 'static, avoid in-place initialization
-                // as that will end up pointing to the stack instead.
-                if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
-                    self.qualif = self.qualif - ConstQualif::PREFER_IN_PLACE;
-                    self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
-                }
-            }
-            Some(hir::MutMutable) => {
-                // `&mut expr` means expr could be mutated, unless it's zero-sized.
-                if self.qualif.intersects(ConstQualif::NON_ZERO_SIZED) {
-                    if self.mode == Mode::Var {
-                        outer = outer | ConstQualif::NOT_CONST;
-                        self.add_qualif(ConstQualif::MUTABLE_MEM);
-                    }
-                }
-                if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
-                    self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
-                }
-            }
-            None => {}
+        if self.mut_rvalue_borrows.remove(&ex.id) {
+            self.promotable = false;
         }
 
-        if self.mode == Mode::Var && !self.qualif.intersects(ConstQualif::NOT_CONST) {
+        if self.in_fn && self.promotable {
             match eval_const_expr_partial(self.tcx, ex, ExprTypeChecked, None) {
                 Ok(_) => {}
                 Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) |
@@ -448,9 +239,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
             }
         }
 
-        self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif);
-        // Don't propagate certain flags.
-        self.qualif = outer | (self.qualif - ConstQualif::HAS_STATIC_BORROWS);
+        self.tcx.rvalue_promotable_to_static.borrow_mut().insert(ex.id, self.promotable);
+        self.promotable &= outer;
     }
 }
 
@@ -463,7 +253,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
 fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) {
     match node_ty.sty {
         ty::TyAdt(def, _) if def.has_dtor() => {
-            v.add_qualif(ConstQualif::NEEDS_DROP);
+            v.promotable = false;
         }
         _ => {}
     }
@@ -473,17 +263,17 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
         hir::ExprUnary(..) |
         hir::ExprBinary(..) |
         hir::ExprIndex(..) if v.tcx.tables().method_map.contains_key(&method_call) => {
-            v.add_qualif(ConstQualif::NOT_CONST);
+            v.promotable = false;
         }
         hir::ExprBox(_) => {
-            v.add_qualif(ConstQualif::NOT_CONST);
+            v.promotable = false;
         }
         hir::ExprUnary(op, ref inner) => {
             match v.tcx.tables().node_id_to_type(inner.id).sty {
                 ty::TyRawPtr(_) => {
                     assert!(op == hir::UnDeref);
 
-                    v.add_qualif(ConstQualif::NOT_CONST);
+                    v.promotable = false;
                 }
                 _ => {}
             }
@@ -495,7 +285,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
                             op.node == hir::BiLe || op.node == hir::BiLt ||
                             op.node == hir::BiGe || op.node == hir::BiGt);
 
-                    v.add_qualif(ConstQualif::NOT_CONST);
+                    v.promotable = false;
                 }
                 _ => {}
             }
@@ -505,7 +295,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
             match v.tcx.cast_kinds.borrow().get(&from.id) {
                 None => span_bug!(e.span, "no kind for cast"),
                 Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
-                    v.add_qualif(ConstQualif::NOT_CONST);
+                    v.promotable = false;
                 }
                 _ => {}
             }
@@ -513,33 +303,24 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
         hir::ExprPath(ref qpath) => {
             let def = v.tcx.tables().qpath_def(qpath, e.id);
             match def {
-                Def::VariantCtor(_, CtorKind::Const) => {
-                    // Size is determined by the whole enum, may be non-zero.
-                    v.add_qualif(ConstQualif::NON_ZERO_SIZED);
-                }
                 Def::VariantCtor(..) | Def::StructCtor(..) |
                 Def::Fn(..) | Def::Method(..) => {}
-                Def::Static(..) => {
-                    match v.mode {
-                        Mode::Static | Mode::StaticMut => {}
-                        Mode::Const | Mode::ConstFn => {}
-                        Mode::Var => v.add_qualif(ConstQualif::NOT_CONST)
-                    }
-                }
-                Def::Const(did) | Def::AssociatedConst(did) => {
-                    let substs = Some(v.tcx.tables().node_id_item_substs(e.id)
-                        .unwrap_or_else(|| v.tcx.intern_substs(&[])));
-                    if let Some((expr, _)) = lookup_const_by_id(v.tcx, did, substs) {
-                        let inner = v.global_expr(Mode::Const, expr);
-                        v.add_qualif(inner);
-                    }
-                }
-                Def::Local(..) if v.mode == Mode::ConstFn => {
-                    // Sadly, we can't determine whether the types are zero-sized.
-                    v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED);
+                Def::AssociatedConst(_) => v.add_type(node_ty),
+                Def::Const(did) => {
+                    v.promotable &= if let Some(node_id) = v.tcx.map.as_local_node_id(did) {
+                        match v.tcx.map.expect_item(node_id).node {
+                            hir::ItemConst(_, body) => {
+                                v.visit_nested_body(body);
+                                v.tcx.rvalue_promotable_to_static.borrow()[&body.node_id]
+                            }
+                            _ => false
+                        }
+                    } else {
+                        v.tcx.sess.cstore.const_is_rvalue_promotable_to_static(did)
+                    };
                 }
                 _ => {
-                    v.add_qualif(ConstQualif::NOT_CONST);
+                    v.promotable = false;
                 }
             }
         }
@@ -560,65 +341,48 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
             } else {
                 Def::Err
             };
-            let is_const = match def {
+            match def {
                 Def::StructCtor(_, CtorKind::Fn) |
-                Def::VariantCtor(_, CtorKind::Fn) => {
-                    // `NON_ZERO_SIZED` is about the call result, not about the ctor itself.
-                    v.add_qualif(ConstQualif::NON_ZERO_SIZED);
-                    true
-                }
+                Def::VariantCtor(_, CtorKind::Fn) => {}
                 Def::Fn(did) => {
-                    v.handle_const_fn_call(e, did, node_ty)
+                    v.handle_const_fn_call(did, node_ty)
                 }
                 Def::Method(did) => {
                     match v.tcx.associated_item(did).container {
                         ty::ImplContainer(_) => {
-                            v.handle_const_fn_call(e, did, node_ty)
+                            v.handle_const_fn_call(did, node_ty)
                         }
-                        ty::TraitContainer(_) => false
+                        ty::TraitContainer(_) => v.promotable = false
                     }
                 }
-                _ => false
-            };
-            if !is_const {
-                v.add_qualif(ConstQualif::NOT_CONST);
+                _ => v.promotable = false
             }
         }
         hir::ExprMethodCall(..) => {
             let method = v.tcx.tables().method_map[&method_call];
-            let is_const = match v.tcx.associated_item(method.def_id).container {
-                ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty),
-                ty::TraitContainer(_) => false
-            };
-            if !is_const {
-                v.add_qualif(ConstQualif::NOT_CONST);
+            match v.tcx.associated_item(method.def_id).container {
+                ty::ImplContainer(_) => v.handle_const_fn_call(method.def_id, node_ty),
+                ty::TraitContainer(_) => v.promotable = false
             }
         }
         hir::ExprStruct(..) => {
             if let ty::TyAdt(adt, ..) = v.tcx.tables().expr_ty(e).sty {
                 // unsafe_cell_type doesn't necessarily exist with no_core
                 if Some(adt.did) == v.tcx.lang_items.unsafe_cell_type() {
-                    v.add_qualif(ConstQualif::MUTABLE_MEM);
+                    v.promotable = false;
                 }
             }
         }
 
         hir::ExprLit(_) |
-        hir::ExprAddrOf(..) => {
-            v.add_qualif(ConstQualif::NON_ZERO_SIZED);
-        }
-
-        hir::ExprRepeat(..) => {
-            v.add_qualif(ConstQualif::PREFER_IN_PLACE);
-        }
+        hir::ExprAddrOf(..) |
+        hir::ExprRepeat(..) => {}
 
         hir::ExprClosure(..) => {
             // Paths in constant contexts cannot refer to local variables,
             // as there are none, and thus closures can't have upvars there.
             if v.tcx.with_freevars(e.id, |fv| !fv.is_empty()) {
-                assert!(v.mode == Mode::Var,
-                        "global closures can't capture anything");
-                v.add_qualif(ConstQualif::NOT_CONST);
+                v.promotable = false;
             }
         }
 
@@ -647,7 +411,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
         hir::ExprAssign(..) |
         hir::ExprAssignOp(..) |
         hir::ExprInlineAsm(..) => {
-            v.add_qualif(ConstQualif::NOT_CONST);
+            v.promotable = false;
         }
     }
 }
@@ -666,7 +430,7 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp
         Some(Adjust::DerefRef { autoderefs, .. }) => {
             if (0..autoderefs as u32)
                 .any(|autoderef| v.tcx.tables().is_overloaded_autoderef(e.id, autoderef)) {
-                v.add_qualif(ConstQualif::NOT_CONST);
+                v.promotable = false;
             }
         }
     }
@@ -676,9 +440,10 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     tcx.visit_all_item_likes_in_krate(DepNode::CheckConst,
                                       &mut CheckCrateVisitor {
                                           tcx: tcx,
-                                          mode: Mode::Var,
-                                          qualif: ConstQualif::NOT_CONST,
-                                          rvalue_borrows: NodeMap(),
+                                          in_fn: false,
+                                          promotable: false,
+                                          mut_rvalue_borrows: NodeSet(),
+                                          param_env: tcx.empty_parameter_environment(),
                                       }.as_deep_visitor());
     tcx.sess.abort_if_errors();
 }
@@ -687,24 +452,9 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
     fn consume(&mut self,
                _consume_id: ast::NodeId,
                _consume_span: Span,
-               cmt: mc::cmt,
-               _mode: euv::ConsumeMode) {
-        let mut cur = &cmt;
-        loop {
-            match cur.cat {
-                Categorization::StaticItem => {
-                    break;
-                }
-                Categorization::Deref(ref cmt, ..) |
-                Categorization::Downcast(ref cmt, _) |
-                Categorization::Interior(ref cmt, _) => cur = cmt,
+               _cmt: mc::cmt,
+               _mode: euv::ConsumeMode) {}
 
-                Categorization::Rvalue(..) |
-                Categorization::Upvar(..) |
-                Categorization::Local(..) => break,
-            }
-        }
-    }
     fn borrow(&mut self,
               borrow_id: ast::NodeId,
               _borrow_span: Span,
@@ -731,21 +481,9 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
                         // Ignore the dummy immutable borrow created by EUV.
                         break;
                     }
-                    let mutbl = bk.to_mutbl_lossy();
-                    if mutbl == hir::MutMutable && self.mode == Mode::StaticMut {
-                        // Mutable slices are the only `&mut` allowed in
-                        // globals, but only in `static mut`, nowhere else.
-                        // FIXME: This exception is really weird... there isn't
-                        // any fundamental reason to restrict this based on
-                        // type of the expression.  `&mut [1]` has exactly the
-                        // same representation as &mut 1.
-                        match cmt.ty.sty {
-                            ty::TyArray(..) |
-                            ty::TySlice(_) => break,
-                            _ => {}
-                        }
+                    if bk.to_mutbl_lossy() == hir::MutMutable {
+                        self.mut_rvalue_borrows.insert(borrow_id);
                     }
-                    self.record_borrow(borrow_id, mutbl);
                     break;
                 }
                 Categorization::StaticItem => {
diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs
index f7e026866e2df..65a60732fc807 100644
--- a/src/librustc_passes/hir_stats.rs
+++ b/src/librustc_passes/hir_stats.rs
@@ -115,6 +115,11 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         self.visit_item(nested_item)
     }
 
+    fn visit_nested_trait_item(&mut self, trait_item_id: hir::TraitItemId) {
+        let nested_trait_item = self.krate.unwrap().trait_item(trait_item_id);
+        self.visit_trait_item(nested_trait_item)
+    }
+
     fn visit_nested_impl_item(&mut self, impl_item_id: hir::ImplItemId) {
         let nested_impl_item = self.krate.unwrap().impl_item(impl_item_id);
         self.visit_impl_item(nested_impl_item)
@@ -172,7 +177,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
     fn visit_fn(&mut self,
                 fk: hir_visit::FnKind<'v>,
                 fd: &'v hir::FnDecl,
-                b: hir::ExprId,
+                b: hir::BodyId,
                 s: Span,
                 id: NodeId) {
         self.record("FnDecl", Id::None, fd);
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index 10f464a9901d0..df9fe00e9a88e 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -84,7 +84,7 @@ impl<'a, 'ast> Visitor<'ast> for CheckLoopVisitor<'a, 'ast> {
                 self.with_context(Loop(LoopKind::Loop(source)), |v| v.visit_block(&b));
             }
             hir::ExprClosure(.., b, _) => {
-                self.with_context(Closure, |v| v.visit_body(b));
+                self.with_context(Closure, |v| v.visit_nested_body(b));
             }
             hir::ExprBreak(label, ref opt_expr) => {
                 if opt_expr.is_some() {
diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs
index ddb5af1e80c34..3da4f24b6c2fe 100644
--- a/src/librustc_passes/rvalues.rs
+++ b/src/librustc_passes/rvalues.rs
@@ -39,7 +39,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> {
     fn visit_fn(&mut self,
                 fk: intravisit::FnKind<'tcx>,
                 fd: &'tcx hir::FnDecl,
-                b: hir::ExprId,
+                b: hir::BodyId,
                 s: Span,
                 fn_id: ast::NodeId) {
         // FIXME (@jroesch) change this to be an inference context
@@ -50,9 +50,9 @@ impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> {
                 tcx: infcx.tcx,
                 param_env: &param_env
             };
-            let body = infcx.tcx.map.expr(b);
+            let body = infcx.tcx.map.body(b);
             let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
-            euv.walk_fn(fd, body);
+            euv.consume_body(body);
         });
         intravisit::walk_fn(self, fk, fd, b, s, fn_id)
     }
diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs
index b5be4aa5e64e2..ba4fc57276b2c 100644
--- a/src/librustc_passes/static_recursion.rs
+++ b/src/librustc_passes/static_recursion.rs
@@ -30,7 +30,7 @@ struct CheckCrateVisitor<'a, 'ast: 'a> {
     // variant definitions with the discriminant expression that applies to
     // each one. If the variant uses the default values (starting from `0`),
     // then `None` is stored.
-    discriminant_map: NodeMap<Option<&'ast hir::Expr>>,
+    discriminant_map: NodeMap<Option<hir::BodyId>>,
     detected_recursive_ids: NodeSet,
 }
 
@@ -66,7 +66,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> {
 
     fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
         match ti.node {
-            hir::ConstTraitItem(_, ref default) => {
+            hir::TraitItemKind::Const(_, ref default) => {
                 if let Some(_) = *default {
                     let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &ti.span);
                     recursion_visitor.visit_trait_item(ti);
@@ -108,7 +108,7 @@ struct CheckItemRecursionVisitor<'a, 'b: 'a, 'ast: 'b> {
     root_span: &'b Span,
     sess: &'b Session,
     ast_map: &'b ast_map::Map<'ast>,
-    discriminant_map: &'a mut NodeMap<Option<&'ast hir::Expr>>,
+    discriminant_map: &'a mut NodeMap<Option<hir::BodyId>>,
     idstack: Vec<ast::NodeId>,
     detected_recursive_ids: &'a mut NodeSet,
 }
@@ -189,7 +189,7 @@ impl<'a, 'b: 'a, 'ast: 'b> CheckItemRecursionVisitor<'a, 'b, 'ast> {
             variant_stack.push(variant.node.data.id());
             // When we find an expression, every variant currently on the stack
             // is affected by that expression.
-            if let Some(ref expr) = variant.node.disr_expr {
+            if let Some(expr) = variant.node.disr_expr {
                 for id in &variant_stack {
                     self.discriminant_map.insert(*id, Some(expr));
                 }
@@ -226,19 +226,15 @@ impl<'a, 'b: 'a, 'ast: 'b> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'b, '
                      _: &'ast hir::Generics,
                      _: ast::NodeId) {
         let variant_id = variant.node.data.id();
-        let maybe_expr;
-        if let Some(get_expr) = self.discriminant_map.get(&variant_id) {
-            // This is necessary because we need to let the `discriminant_map`
-            // borrow fall out of scope, so that we can reborrow farther down.
-            maybe_expr = (*get_expr).clone();
-        } else {
+        let maybe_expr = *self.discriminant_map.get(&variant_id).unwrap_or_else(|| {
             span_bug!(variant.span,
                       "`check_static_recursion` attempted to visit \
                       variant with unknown discriminant")
-        }
+        });
         // If `maybe_expr` is `None`, that's because no discriminant is
         // specified that affects this variant. Thus, no risk of recursion.
         if let Some(expr) = maybe_expr {
+            let expr = &self.ast_map.body(expr).value;
             self.with_item_id_pushed(expr.id, |v| intravisit::walk_expr(v, expr), expr.span);
         }
     }
diff --git a/src/librustc_plugin/build.rs b/src/librustc_plugin/build.rs
index 75046f6aeb874..34ebd12de9c18 100644
--- a/src/librustc_plugin/build.rs
+++ b/src/librustc_plugin/build.rs
@@ -33,6 +33,9 @@ impl<'v> ItemLikeVisitor<'v> for RegistrarFinder {
         }
     }
 
+    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+    }
+
     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
     }
 }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index ca3e4e1c762c7..81863a3fadfd3 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -160,21 +160,19 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
             }
             hir::ItemImpl(.., None, _, ref impl_item_refs) => {
                 for impl_item_ref in impl_item_refs {
-                    let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
-                    if impl_item.vis == hir::Public {
-                        self.update(impl_item.id, item_level);
+                    if impl_item_ref.vis == hir::Public {
+                        self.update(impl_item_ref.id.node_id, item_level);
                     }
                 }
             }
             hir::ItemImpl(.., Some(_), _, ref impl_item_refs) => {
                 for impl_item_ref in impl_item_refs {
-                    let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
-                    self.update(impl_item.id, item_level);
+                    self.update(impl_item_ref.id.node_id, item_level);
                 }
             }
-            hir::ItemTrait(.., ref trait_items) => {
-                for trait_item in trait_items {
-                    self.update(trait_item.id, item_level);
+            hir::ItemTrait(.., ref trait_item_refs) => {
+                for trait_item_ref in trait_item_refs {
+                    self.update(trait_item_ref.id.node_id, item_level);
                 }
             }
             hir::ItemStruct(ref def, _) | hir::ItemUnion(ref def, _) => {
@@ -214,15 +212,16 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
                     self.reach(item.id).generics().predicates().item_type();
                 }
             }
-            hir::ItemTrait(.., ref trait_items) => {
+            hir::ItemTrait(.., ref trait_item_refs) => {
                 if item_level.is_some() {
                     self.reach(item.id).generics().predicates();
 
-                    for trait_item in trait_items {
-                        let mut reach = self.reach(trait_item.id);
+                    for trait_item_ref in trait_item_refs {
+                        let mut reach = self.reach(trait_item_ref.id.node_id);
                         reach.generics().predicates();
 
-                        if let hir::TypeTraitItem(_, None) = trait_item.node {
+                        if trait_item_ref.kind == hir::AssociatedItemKind::Type &&
+                           !trait_item_ref.defaultness.has_value() {
                             // No type to visit.
                         } else {
                             reach.item_type();
@@ -231,12 +230,12 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
                 }
             }
             // Visit everything except for private impl items
-            hir::ItemImpl(.., ref trait_ref, _, ref impl_items) => {
+            hir::ItemImpl(.., ref trait_ref, _, ref impl_item_refs) => {
                 if item_level.is_some() {
                     self.reach(item.id).generics().predicates().impl_trait_ref();
 
-                    for impl_item in impl_items {
-                        let id = impl_item.id.node_id;
+                    for impl_item_ref in impl_item_refs {
+                        let id = impl_item_ref.id.node_id;
                         if trait_ref.is_some() || self.get(id).is_some() {
                             self.reach(id).generics().predicates().item_type();
                         }
@@ -789,22 +788,19 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
                     // methods will be visible as `Public::foo`.
                     let mut found_pub_static = false;
                     for impl_item_ref in impl_item_refs {
-                        let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
-                        match impl_item.node {
-                            hir::ImplItemKind::Const(..) => {
-                                if self.item_is_public(&impl_item.id, &impl_item.vis) {
+                        if self.item_is_public(&impl_item_ref.id.node_id, &impl_item_ref.vis) {
+                            let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
+                            match impl_item_ref.kind {
+                                hir::AssociatedItemKind::Const => {
                                     found_pub_static = true;
                                     intravisit::walk_impl_item(self, impl_item);
                                 }
-                            }
-                            hir::ImplItemKind::Method(ref sig, _) => {
-                                if !sig.decl.has_self() &&
-                                        self.item_is_public(&impl_item.id, &impl_item.vis) {
+                                hir::AssociatedItemKind::Method { has_self: false } => {
                                     found_pub_static = true;
                                     intravisit::walk_impl_item(self, impl_item);
                                 }
+                                _ => {}
                             }
-                            _ => {}
                         }
                     }
                     if found_pub_static {
@@ -1092,14 +1088,15 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
                 self.inner_visibility = item_visibility;
                 intravisit::walk_item(self, item);
             }
-            hir::ItemTrait(.., ref trait_items) => {
+            hir::ItemTrait(.., ref trait_item_refs) => {
                 self.check(item.id, item_visibility).generics().predicates();
 
-                for trait_item in trait_items {
-                    let mut check = self.check(trait_item.id, item_visibility);
+                for trait_item_ref in trait_item_refs {
+                    let mut check = self.check(trait_item_ref.id.node_id, item_visibility);
                     check.generics().predicates();
 
-                    if let hir::TypeTraitItem(_, None) = trait_item.node {
+                    if trait_item_ref.kind == hir::AssociatedItemKind::Type &&
+                       !trait_item_ref.defaultness.has_value() {
                         // No type to visit.
                     } else {
                         check.item_type();
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index a0af4c4565359..865195d3db488 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -571,6 +571,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
     fn visit_ty(&mut self, ty: &'tcx Ty) {
         if let TyKind::Path(ref qself, ref path) = ty.node {
             self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
+        } else if let TyKind::ImplicitSelf = ty.node {
+            let self_ty = keywords::SelfType.ident();
+            let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.span))
+                          .map_or(Def::Err, |d| d.def());
+            self.record_def(ty.id, PathResolution::new(def));
+        } else if let TyKind::Array(ref element, ref length) = ty.node {
+            self.visit_ty(element);
+            self.with_constant_rib(|this| {
+                this.visit_expr(length);
+            });
+            return;
         }
         visit::walk_ty(self, ty);
     }
@@ -741,6 +752,13 @@ impl<'a> LexicalScopeBinding<'a> {
             _ => None,
         }
     }
+
+    fn def(self) -> Def {
+        match self {
+            LexicalScopeBinding::Item(binding) => binding.def(),
+            LexicalScopeBinding::Def(def) => def,
+        }
+    }
 }
 
 #[derive(Clone)]
@@ -2721,6 +2739,13 @@ impl<'a> Resolver<'a> {
                     self.visit_ty(ty);
                 }
             }
+
+            ExprKind::Repeat(ref element, ref count) => {
+                self.visit_expr(element);
+                self.with_constant_rib(|this| {
+                    this.visit_expr(count);
+                });
+            }
             ExprKind::Call(ref callee, ref arguments) => {
                 self.resolve_expr(callee, Some(&expr.node));
                 for argument in arguments {
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 491521a323949..43e3b1dd2b50a 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -349,7 +349,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     match item.node {
                         hir::ItemImpl(.., ref ty, _) => {
                             let mut result = String::from("<");
-                            result.push_str(&rustc::hir::print::ty_to_string(&ty));
+                            result.push_str(&self.tcx.map.node_to_pretty_string(ty.id));
 
                             let trait_id = self.tcx.trait_id_of_impl(impl_id);
                             let mut decl_id = None;
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index 84222bfe56eee..2bc42a461528d 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -202,8 +202,6 @@ use rustc::mir::{self, Location};
 use rustc::mir::visit as mir_visit;
 use rustc::mir::visit::Visitor as MirVisitor;
 
-use rustc_const_eval as const_eval;
-
 use syntax::abi::Abi;
 use syntax_pos::DUMMY_SP;
 use base::custom_coerce_unsize_info;
@@ -344,19 +342,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
 
             recursion_depth_reset = None;
 
-            // Scan the MIR in order to find function calls, closures, and
-            // drop-glue
-            let mir = scx.tcx().item_mir(def_id);
-
-            let empty_substs = scx.empty_substs_for_def_id(def_id);
-            let visitor = MirNeighborCollector {
-                scx: scx,
-                mir: &mir,
-                output: &mut neighbors,
-                param_substs: empty_substs
-            };
-
-            visit_mir_and_promoted(visitor, &mir);
+            collect_neighbours(scx, Instance::mono(scx, def_id), &mut neighbors);
         }
         TransItem::Fn(instance) => {
             // Keep track of the monomorphization recursion depth
@@ -365,18 +351,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
                                                                recursion_depths));
             check_type_length_limit(scx.tcx(), instance);
 
-            // Scan the MIR in order to find function calls, closures, and
-            // drop-glue
-            let mir = scx.tcx().item_mir(instance.def);
-
-            let visitor = MirNeighborCollector {
-                scx: scx,
-                mir: &mir,
-                output: &mut neighbors,
-                param_substs: instance.substs
-            };
-
-            visit_mir_and_promoted(visitor, &mir);
+            collect_neighbours(scx, instance, &mut neighbors);
         }
     }
 
@@ -563,33 +538,12 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                     // This is not a callee, but we still have to look for
                     // references to `const` items
                     if let mir::Literal::Item { def_id, substs } = constant.literal {
-                        let tcx = self.scx.tcx();
                         let substs = monomorphize::apply_param_substs(self.scx,
                                                                       self.param_substs,
                                                                       &substs);
 
-                        // If the constant referred to here is an associated
-                        // item of a trait, we need to resolve it to the actual
-                        // constant in the corresponding impl. Luckily
-                        // const_eval::lookup_const_by_id() does that for us.
-                        if let Some((expr, _)) = const_eval::lookup_const_by_id(tcx,
-                                                                                def_id,
-                                                                                Some(substs)) {
-                            // The hir::Expr we get here is the initializer of
-                            // the constant, what we really want is the item
-                            // DefId.
-                            let const_node_id = tcx.map.get_parent(expr.id);
-                            let def_id = if tcx.map.is_inlined_node_id(const_node_id) {
-                                tcx.sess.cstore.defid_for_inlined_node(const_node_id).unwrap()
-                            } else {
-                                tcx.map.local_def_id(const_node_id)
-                            };
-
-                            collect_const_item_neighbours(self.scx,
-                                                          def_id,
-                                                          substs,
-                                                          self.output);
-                        }
+                        let instance = Instance::new(def_id, substs).resolve_const(self.scx);
+                        collect_neighbours(self.scx, instance, self.output);
                     }
 
                     None
@@ -1122,6 +1076,11 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
         }
     }
 
+    fn visit_trait_item(&mut self, _: &'v hir::TraitItem) {
+        // Even if there's a default body with no explicit generics,
+        // it's still generic over some `Self: Trait`, so not a root.
+    }
+
     fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
         match ii.node {
             hir::ImplItemKind::Method(hir::MethodSig {
@@ -1228,29 +1187,20 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
     }
 }
 
-// There are no translation items for constants themselves but their
-// initializers might still contain something that produces translation items,
-// such as cast that introduce a new vtable.
-fn collect_const_item_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
-                                           def_id: DefId,
-                                           substs: &'tcx Substs<'tcx>,
-                                           output: &mut Vec<TransItem<'tcx>>)
+/// Scan the MIR in order to find function calls, closures, and drop-glue
+fn collect_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+                                instance: Instance<'tcx>,
+                                output: &mut Vec<TransItem<'tcx>>)
 {
-    // Scan the MIR in order to find function calls, closures, and
-    // drop-glue
-    let mir = scx.tcx().item_mir(def_id);
+    let mir = scx.tcx().item_mir(instance.def);
 
-    let visitor = MirNeighborCollector {
+    let mut visitor = MirNeighborCollector {
         scx: scx,
         mir: &mir,
         output: output,
-        param_substs: substs
+        param_substs: instance.substs
     };
 
-    visit_mir_and_promoted(visitor, &mir);
-}
-
-fn visit_mir_and_promoted<'tcx, V: MirVisitor<'tcx>>(mut visitor: V, mir: &mir::Mir<'tcx>) {
     visitor.visit_mir(&mir);
     for promoted in &mir.promoted {
         visitor.visit_mir(promoted);
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index f292a70965004..d9179d6a6fa73 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -737,14 +737,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         &self.local().drop_glues
     }
 
-    pub fn local_node_for_inlined_defid<'a>(&'a self, def_id: DefId) -> Option<ast::NodeId> {
-        self.sess().cstore.local_node_for_inlined_defid(def_id)
-    }
-
-    pub fn defid_for_inlined_node<'a>(&'a self, node_id: ast::NodeId) -> Option<DefId> {
-        self.sess().cstore.defid_for_inlined_node(node_id)
-    }
-
     pub fn instances<'a>(&'a self) -> &'a RefCell<FxHashMap<Instance<'tcx>, ValueRef>> {
         &self.local().instances
     }
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 08f68f8d49c78..1cedaa0a4e1a4 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -18,7 +18,6 @@ use rustc::hir::def_id::DefId;
 use rustc::infer::TransNormalize;
 use rustc::mir;
 use rustc::mir::tcx::LvalueTy;
-use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::cast::{CastTy, IntTy};
 use rustc::ty::subst::Substs;
@@ -36,7 +35,7 @@ use type_::Type;
 use value::Value;
 
 use syntax::ast;
-use syntax_pos::{Span, DUMMY_SP};
+use syntax_pos::Span;
 
 use std::fmt;
 use std::ptr;
@@ -238,24 +237,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
     }
 
     fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
-                 mut instance: Instance<'tcx>,
+                 instance: Instance<'tcx>,
                  args: IndexVec<mir::Local, Const<'tcx>>)
                  -> Result<Const<'tcx>, ConstEvalErr> {
-        // Try to resolve associated constants.
-        if let Some(trait_id) = ccx.tcx().trait_of_item(instance.def) {
-            let trait_ref = ty::TraitRef::new(trait_id, instance.substs);
-            let trait_ref = ty::Binder(trait_ref);
-            let vtable = common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref);
-            if let traits::VtableImpl(vtable_impl) = vtable {
-                let name = ccx.tcx().item_name(instance.def);
-                let ac = ccx.tcx().associated_items(vtable_impl.impl_def_id)
-                    .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
-                if let Some(ac) = ac {
-                    instance = Instance::new(ac.def_id, vtable_impl.substs);
-                }
-            }
-        }
-
+        let instance = instance.resolve_const(ccx.shared());
         let mir = ccx.tcx().item_mir(instance.def);
         MirConstContext::new(ccx, &mir, instance.substs, args).trans()
     }
diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs
index 8f05cc793ef22..4b31d5b7f88de 100644
--- a/src/librustc_trans/monomorphize.rs
+++ b/src/librustc_trans/monomorphize.rs
@@ -11,11 +11,15 @@
 use common::*;
 use rustc::hir::def_id::DefId;
 use rustc::infer::TransNormalize;
+use rustc::traits;
 use rustc::ty::fold::{TypeFolder, TypeFoldable};
 use rustc::ty::subst::{Subst, Substs};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::util::ppaux;
 use rustc::util::common::MemoizationMap;
+
+use syntax::codemap::DUMMY_SP;
+
 use std::fmt;
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@@ -30,15 +34,35 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
     }
 }
 
-impl<'tcx> Instance<'tcx> {
+impl<'a, 'tcx> Instance<'tcx> {
     pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
                -> Instance<'tcx> {
         assert!(substs.regions().all(|&r| r == ty::ReErased));
         Instance { def: def_id, substs: substs }
     }
-    pub fn mono<'a>(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'tcx> {
+
+    pub fn mono(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'tcx> {
         Instance::new(def_id, scx.empty_substs_for_def_id(def_id))
     }
+
+    /// For associated constants from traits, return the impl definition.
+    pub fn resolve_const(&self, scx: &SharedCrateContext<'a, 'tcx>) -> Self {
+        if let Some(trait_id) = scx.tcx().trait_of_item(self.def) {
+            let trait_ref = ty::TraitRef::new(trait_id, self.substs);
+            let trait_ref = ty::Binder(trait_ref);
+            let vtable = fulfill_obligation(scx, DUMMY_SP, trait_ref);
+            if let traits::VtableImpl(vtable_impl) = vtable {
+                let name = scx.tcx().item_name(self.def);
+                let ac = scx.tcx().associated_items(vtable_impl.impl_def_id)
+                    .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
+                if let Some(ac) = ac {
+                    return Instance::new(ac.def_id, vtable_impl.substs);
+                }
+            }
+        }
+
+        *self
+    }
 }
 
 /// Monomorphizes a type from the AST by first applying the in-scope
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 598003a392512..75c25a605af25 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -50,10 +50,9 @@
 
 use rustc_const_eval::eval_length;
 use rustc_data_structures::accumulate_vec::AccumulateVec;
-use hir::{self, SelfKind};
+use hir;
 use hir::def::Def;
 use hir::def_id::DefId;
-use hir::print as pprust;
 use middle::resolve_lifetime as rl;
 use rustc::lint;
 use rustc::ty::subst::{Kind, Subst, Substs};
@@ -227,6 +226,7 @@ pub fn ast_region_to_region<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
 }
 
 fn report_elision_failure(
+    tcx: TyCtxt,
     db: &mut DiagnosticBuilder,
     params: Vec<ElisionFailureInfo>)
 {
@@ -241,13 +241,14 @@ fn report_elision_failure(
 
     for (i, info) in elided_params.into_iter().enumerate() {
         let ElisionFailureInfo {
-            name, lifetime_count: n, have_bound_regions
+            parent, index, lifetime_count: n, have_bound_regions
         } = info;
 
-        let help_name = if name.is_empty() {
-            format!("argument {}", i + 1)
+        let help_name = if let Some(body) = parent {
+            let arg = &tcx.map.body(body).arguments[index];
+            format!("`{}`", tcx.map.node_to_pretty_string(arg.pat.id))
         } else {
-            format!("`{}`", name)
+            format!("argument {}", index + 1)
         };
 
         m.push_str(&(if n == 1 {
@@ -315,7 +316,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     err.span_label(ampersand_span, &format!("expected lifetime parameter"));
 
                     if let Some(params) = params {
-                        report_elision_failure(&mut err, params);
+                        report_elision_failure(self.tcx(), &mut err, params);
                     }
                     err.emit();
                     ty::ReStatic
@@ -540,15 +541,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     /// corresponding to each input type/pattern.
     fn find_implied_output_region<I>(&self,
                                      input_tys: &[Ty<'tcx>],
-                                     input_pats: I) -> ElidedLifetime
-        where I: Iterator<Item=String>
+                                     parent: Option<hir::BodyId>,
+                                     input_indices: I) -> ElidedLifetime
+        where I: Iterator<Item=usize>
     {
         let tcx = self.tcx();
         let mut lifetimes_for_params = Vec::with_capacity(input_tys.len());
         let mut possible_implied_output_region = None;
         let mut lifetimes = 0;
 
-        for input_type in input_tys.iter() {
+        for (input_type, index) in input_tys.iter().zip(input_indices) {
             let mut regions = FxHashSet();
             let have_bound_regions = tcx.collect_regions(input_type, &mut regions);
 
@@ -564,11 +566,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 possible_implied_output_region = regions.iter().cloned().next();
             }
 
-            // Use a placeholder for `name` because computing it can be
-            // expensive and we don't want to do it until we know it's
-            // necessary.
             lifetimes_for_params.push(ElisionFailureInfo {
-                name: String::new(),
+                parent: parent,
+                index: index,
                 lifetime_count: regions.len(),
                 have_bound_regions: have_bound_regions
             });
@@ -577,11 +577,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         if lifetimes == 1 {
             Ok(*possible_implied_output_region.unwrap())
         } else {
-            // Fill in the expensive `name` fields now that we know they're
-            // needed.
-            for (info, input_pat) in lifetimes_for_params.iter_mut().zip(input_pats) {
-                info.name = input_pat;
-            }
             Err(Some(lifetimes_for_params))
         }
     }
@@ -618,8 +613,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         let inputs = self.tcx().mk_type_list(data.inputs.iter().map(|a_t| {
             self.ast_ty_arg_to_ty(&binding_rscope, None, region_substs, a_t)
         }));
-        let input_params = iter::repeat(String::new()).take(inputs.len());
-        let implied_output_region = self.find_implied_output_region(&inputs, input_params);
+        let input_params = 0..inputs.len();
+        let implied_output_region = self.find_implied_output_region(&inputs, None, input_params);
 
         let (output, output_span) = match data.output {
             Some(ref output_ty) => {
@@ -689,7 +684,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             }
             _ => {
                 span_fatal!(self.tcx().sess, path.span, E0245, "`{}` is not a trait",
-                            path);
+                            self.tcx().map.node_to_pretty_string(trait_ref.ref_id));
             }
         }
     }
@@ -976,7 +971,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 let mut err = struct_span_err!(tcx.sess, ty.span, E0178,
                                                "expected a path on the left-hand side \
                                                 of `+`, not `{}`",
-                                               pprust::ty_to_string(ty));
+                                               tcx.map.node_to_pretty_string(ty.id));
                 err.span_label(ty.span, &format!("expected a path"));
                 let hi = bounds.iter().map(|x| match *x {
                     hir::TraitTyParamBound(ref tr, _) => tr.span.hi,
@@ -988,22 +983,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     expn_id: ty.span.expn_id,
                 });
                 match (&ty.node, full_span) {
-                    (&hir::TyRptr(None, ref mut_ty), Some(full_span)) => {
-                        let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" };
+                    (&hir::TyRptr(ref lifetime, ref mut_ty), Some(full_span)) => {
+                        let ty_str = hir::print::to_string(&tcx.map, |s| {
+                            use syntax::print::pp::word;
+                            use syntax::print::pprust::PrintState;
+
+                            word(&mut s.s, "&")?;
+                            s.print_opt_lifetime(lifetime)?;
+                            s.print_mutability(mut_ty.mutbl)?;
+                            s.popen()?;
+                            s.print_type(&mut_ty.ty)?;
+                            s.print_bounds(" +", bounds)?;
+                            s.pclose()
+                        });
                         err.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
-                                            format!("&{}({} +{})",
-                                                    mutbl_str,
-                                                    pprust::ty_to_string(&mut_ty.ty),
-                                                    pprust::bounds_to_string(bounds)));
-                    }
-                    (&hir::TyRptr(Some(ref lt), ref mut_ty), Some(full_span)) => {
-                        let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" };
-                        err.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
-                                            format!("&{} {}({} +{})",
-                                                    pprust::lifetime_to_string(lt),
-                                                    mutbl_str,
-                                                    pprust::ty_to_string(&mut_ty.ty),
-                                                    pprust::bounds_to_string(bounds)));
+                                            ty_str);
                     }
 
                     _ => {
@@ -1572,6 +1566,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                                               bf.abi,
                                                               None,
                                                               &bf.decl,
+                                                              None,
                                                               anon_scope,
                                                               anon_scope);
 
@@ -1664,8 +1659,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 };
                 self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment).0
             }
-            hir::TyArray(ref ty, ref e) => {
-                if let Ok(length) = eval_length(tcx.global_tcx(), &e, "array length") {
+            hir::TyArray(ref ty, length) => {
+                let e = &tcx.map.body(length).value;
+                if let Ok(length) = eval_length(tcx.global_tcx(), e, "array length") {
                     tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length)
                 } else {
                     self.tcx().types.err
@@ -1695,26 +1691,28 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
     pub fn ty_of_arg(&self,
                      rscope: &RegionScope,
-                     a: &hir::Arg,
+                     ty: &hir::Ty,
                      expected_ty: Option<Ty<'tcx>>)
                      -> Ty<'tcx>
     {
-        match a.ty.node {
+        match ty.node {
             hir::TyInfer if expected_ty.is_some() => expected_ty.unwrap(),
-            hir::TyInfer => self.ty_infer(a.ty.span),
-            _ => self.ast_ty_to_ty(rscope, &a.ty),
+            hir::TyInfer => self.ty_infer(ty.span),
+            _ => self.ast_ty_to_ty(rscope, ty),
         }
     }
 
     pub fn ty_of_method(&self,
                         sig: &hir::MethodSig,
-                        untransformed_self_ty: Ty<'tcx>,
+                        opt_self_value_ty: Option<Ty<'tcx>>,
+                        body: Option<hir::BodyId>,
                         anon_scope: Option<AnonTypeScope>)
                         -> &'tcx ty::BareFnTy<'tcx> {
         self.ty_of_method_or_bare_fn(sig.unsafety,
                                      sig.abi,
-                                     Some(untransformed_self_ty),
+                                     opt_self_value_ty,
                                      &sig.decl,
+                                     body,
                                      None,
                                      anon_scope)
     }
@@ -1723,16 +1721,18 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                          unsafety: hir::Unsafety,
                          abi: abi::Abi,
                          decl: &hir::FnDecl,
+                         body: hir::BodyId,
                          anon_scope: Option<AnonTypeScope>)
                          -> &'tcx ty::BareFnTy<'tcx> {
-        self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, None, anon_scope)
+        self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, Some(body), None, anon_scope)
     }
 
     fn ty_of_method_or_bare_fn(&self,
                                unsafety: hir::Unsafety,
                                abi: abi::Abi,
-                               opt_untransformed_self_ty: Option<Ty<'tcx>>,
+                               opt_self_value_ty: Option<Ty<'tcx>>,
                                decl: &hir::FnDecl,
+                               body: Option<hir::BodyId>,
                                arg_anon_scope: Option<AnonTypeScope>,
                                ret_anon_scope: Option<AnonTypeScope>)
                                -> &'tcx ty::BareFnTy<'tcx>
@@ -1743,38 +1743,29 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         // declaration are bound to that function type.
         let rb = MaybeWithAnonTypes::new(BindingRscope::new(), arg_anon_scope);
 
-        // `implied_output_region` is the region that will be assumed for any
-        // region parameters in the return type. In accordance with the rules for
-        // lifetime elision, we can determine it in two ways. First (determined
-        // here), if self is by-reference, then the implied output region is the
-        // region of the self parameter.
-        let (self_ty, explicit_self) = match (opt_untransformed_self_ty, decl.get_self()) {
-            (Some(untransformed_self_ty), Some(explicit_self)) => {
-                let self_type = self.determine_self_type(&rb, untransformed_self_ty,
-                                                         &explicit_self);
-                (Some(self_type), Some(ExplicitSelf::determine(untransformed_self_ty, self_type)))
-            }
-            _ => (None, None),
-        };
+        let input_tys: Vec<Ty> =
+            decl.inputs.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect();
 
-        // HACK(eddyb) replace the fake self type in the AST with the actual type.
-        let arg_params = if self_ty.is_some() {
-            &decl.inputs[1..]
-        } else {
-            &decl.inputs[..]
-        };
-        let arg_tys: Vec<Ty> =
-            arg_params.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect();
+        let has_self = opt_self_value_ty.is_some();
+        let explicit_self = opt_self_value_ty.map(|self_value_ty| {
+            ExplicitSelf::determine(self_value_ty, input_tys[0])
+        });
 
-        // Second, if there was exactly one lifetime (either a substitution or a
-        // reference) in the arguments, then any anonymous regions in the output
-        // have that lifetime.
         let implied_output_region = match explicit_self {
+            // `implied_output_region` is the region that will be assumed for any
+            // region parameters in the return type. In accordance with the rules for
+            // lifetime elision, we can determine it in two ways. First (determined
+            // here), if self is by-reference, then the implied output region is the
+            // region of the self parameter.
             Some(ExplicitSelf::ByReference(region, _)) => Ok(*region),
+
+            // Second, if there was exactly one lifetime (either a substitution or a
+            // reference) in the arguments, then any anonymous regions in the output
+            // have that lifetime.
             _ => {
-                self.find_implied_output_region(&arg_tys,
-                                                arg_params.iter()
-                                                    .map(|a| pprust::pat_to_string(&a.pat)))
+                let arg_tys = &input_tys[has_self as usize..];
+                let arg_params = has_self as usize..input_tys.len();
+                self.find_implied_output_region(arg_tys, body, arg_params)
 
             }
         };
@@ -1793,37 +1784,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             unsafety: unsafety,
             abi: abi,
             sig: ty::Binder(self.tcx().mk_fn_sig(
-                self_ty.into_iter().chain(arg_tys),
+                input_tys.into_iter(),
                 output_ty,
                 decl.variadic
             )),
         })
     }
 
-    fn determine_self_type<'a>(&self,
-                               rscope: &RegionScope,
-                               untransformed_self_ty: Ty<'tcx>,
-                               explicit_self: &hir::ExplicitSelf)
-                               -> Ty<'tcx>
-    {
-        match explicit_self.node {
-            SelfKind::Value(..) => untransformed_self_ty,
-            SelfKind::Region(ref lifetime, mutability) => {
-                let region =
-                    self.opt_ast_region_to_region(
-                                             rscope,
-                                             explicit_self.span,
-                                             lifetime);
-                self.tcx().mk_ref(region,
-                    ty::TypeAndMut {
-                        ty: untransformed_self_ty,
-                        mutbl: mutability
-                    })
-            }
-            SelfKind::Explicit(ref ast_type, _) => self.ast_ty_to_ty(rscope, &ast_type)
-        }
-    }
-
     pub fn ty_of_closure(&self,
         unsafety: hir::Unsafety,
         decl: &hir::FnDecl,
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index ff50ee11b390e..9b86196b3ece2 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -527,7 +527,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let report_unexpected_def = |def: Def| {
             span_err!(tcx.sess, pat.span, E0533,
                       "expected unit struct/variant or constant, found {} `{}`",
-                      def.kind_name(), qpath);
+                      def.kind_name(),
+                      hir::print::to_string(&tcx.map, |s| s.print_qpath(qpath, false)));
         };
 
         // Resolve the path and check the definition for errors.
@@ -568,7 +569,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         };
         let report_unexpected_def = |def: Def| {
             let msg = format!("expected tuple struct/variant, found {} `{}`",
-                              def.kind_name(), qpath);
+                              def.kind_name(),
+                              hir::print::to_string(&tcx.map, |s| s.print_qpath(qpath, false)));
             struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg)
                 .span_label(pat.span, &format!("not a tuple variant or struct")).emit();
             on_error();
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 4fba29def226c..0b9cf38fa0733 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -13,7 +13,6 @@ use super::{DeferredCallResolution, Expectation, FnCtxt, TupleArgumentsFlag};
 use CrateCtxt;
 use hir::def::Def;
 use hir::def_id::{DefId, LOCAL_CRATE};
-use hir::print;
 use rustc::{infer, traits};
 use rustc::ty::{self, LvaluePreference, Ty};
 use syntax::symbol::Symbol;
@@ -203,7 +202,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 if let &ty::TyAdt(adt_def, ..) = t {
                     if adt_def.is_enum() {
                         if let hir::ExprCall(ref expr, _) = call_expr.node {
-                            unit_variant = Some(print::expr_to_string(expr))
+                            unit_variant = Some(self.tcx.map.node_to_pretty_string(expr.id))
                         }
                     }
                 }
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 1d81ed7d35956..9412c9105c7aa 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -25,7 +25,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               expr: &hir::Expr,
                               _capture: hir::CaptureClause,
                               decl: &'gcx hir::FnDecl,
-                              body_id: hir::ExprId,
+                              body_id: hir::BodyId,
                               expected: Expectation<'tcx>)
                               -> Ty<'tcx> {
         debug!("check_expr_closure(expr={:?},expected={:?})",
@@ -39,7 +39,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Some(ty) => self.deduce_expectations_from_expected_type(ty),
             None => (None, None),
         };
-        let body = self.tcx.map.expr(body_id);
+        let body = self.tcx.map.body(body_id);
         self.check_closure(expr, expected_kind, decl, body, expected_sig)
     }
 
@@ -47,7 +47,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                      expr: &hir::Expr,
                      opt_kind: Option<ty::ClosureKind>,
                      decl: &'gcx hir::FnDecl,
-                     body: &'gcx hir::Expr,
+                     body: &'gcx hir::Body,
                      expected_sig: Option<ty::FnSig<'tcx>>)
                      -> Ty<'tcx> {
         debug!("check_closure opt_kind={:?} expected_sig={:?}",
@@ -73,10 +73,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type);
 
-        let fn_sig = self.tcx
-            .liberate_late_bound_regions(self.tcx.region_maps.call_site_extent(expr.id, body.id),
-                                         &fn_ty.sig);
-        let fn_sig = (**self).normalize_associated_types_in(body.span, body.id, &fn_sig);
+        let extent = self.tcx.region_maps.call_site_extent(expr.id, body.value.id);
+        let fn_sig = self.tcx.liberate_late_bound_regions(extent, &fn_ty.sig);
+        let fn_sig = self.inh.normalize_associated_types_in(body.value.span,
+                                                            body.value.id, &fn_sig);
 
         check_fn(self,
                  hir::Unsafety::Normal,
@@ -84,7 +84,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                  &fn_sig,
                  decl,
                  expr.id,
-                 &body);
+                 body);
 
         // Tuple up the arguments and insert the resulting function type into
         // the `closures` table.
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 478de1673170f..be10b77bd8b90 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -8,14 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::hir;
+use rustc::hir::{self, ImplItemKind, TraitItemKind};
 use rustc::infer::{self, InferOk};
 use rustc::middle::free_region::FreeRegionMap;
 use rustc::ty;
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 use rustc::ty::error::{ExpectedFound, TypeError};
 use rustc::ty::subst::{Subst, Substs};
-use rustc::hir::{ImplItemKind, TraitItem_, Ty_};
 use rustc::util::common::ErrorReported;
 
 use syntax::ast;
@@ -450,37 +449,24 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
         TypeError::Mutability => {
             if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
                 let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
-                    TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+                    TraitItemKind::Method(ref trait_m_sig, _) => {
                         trait_m_sig.decl.inputs.iter()
                     }
-                    _ => bug!("{:?} is not a MethodTraitItem", trait_m),
+                    _ => bug!("{:?} is not a TraitItemKind::Method", trait_m),
                 };
 
-                impl_m_iter.zip(trait_m_iter)
-                           .find(|&(ref impl_arg, ref trait_arg)| {
-                               match (&impl_arg.ty.node, &trait_arg.ty.node) {
-                                   (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
-                                   (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => {
-                                       impl_mt.mutbl != trait_mt.mutbl
-                                   }
-                                   _ => false,
-                               }
-                           })
-                           .map(|(ref impl_arg, ref trait_arg)| {
-                               match (impl_arg.to_self(), trait_arg.to_self()) {
-                                   (Some(impl_self), Some(trait_self)) => {
-                                       (impl_self.span, Some(trait_self.span))
-                                   }
-                                   (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
-                                   _ => {
-                                       bug!("impl and trait fns have different first args, impl: \
-                                             {:?}, trait: {:?}",
-                                            impl_arg,
-                                            trait_arg)
-                                   }
-                               }
-                           })
-                           .unwrap_or((cause.span, tcx.map.span_if_local(trait_m.def_id)))
+                impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| {
+                    match (&impl_arg.node, &trait_arg.node) {
+                        (&hir::TyRptr(_, ref impl_mt), &hir::TyRptr(_, ref trait_mt)) |
+                        (&hir::TyPtr(ref impl_mt), &hir::TyPtr(ref trait_mt)) => {
+                            impl_mt.mutbl != trait_mt.mutbl
+                        }
+                        _ => false,
+                    }
+                }).map(|(ref impl_arg, ref trait_arg)| {
+                    (impl_arg.span, Some(trait_arg.span))
+                })
+                .unwrap_or_else(|| (cause.span, tcx.map.span_if_local(trait_m.def_id)))
             } else {
                 (cause.span, tcx.map.span_if_local(trait_m.def_id))
             }
@@ -489,10 +475,10 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
             if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
                 let (trait_m_output, trait_m_iter) =
                     match tcx.map.expect_trait_item(trait_m_node_id).node {
-                        TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+                        TraitItemKind::Method(ref trait_m_sig, _) => {
                             (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter())
                         }
-                        _ => bug!("{:?} is not a MethodTraitItem", trait_m),
+                        _ => bug!("{:?} is not a TraitItemKind::Method", trait_m),
                     };
 
                 let impl_iter = impl_sig.inputs().iter();
@@ -503,7 +489,7 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
                          .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
                              match infcx.sub_types(true, &cause, trait_arg_ty, impl_arg_ty) {
                                  Ok(_) => None,
-                                 Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))),
+                                 Err(_) => Some((impl_arg.span, Some(trait_arg.span))),
                              }
                          })
                          .next()
@@ -688,13 +674,13 @@ fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         let trait_m_node_id = tcx.map.as_local_node_id(trait_m.def_id);
         let trait_span = if let Some(trait_id) = trait_m_node_id {
             match tcx.map.expect_trait_item(trait_id).node {
-                TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+                TraitItemKind::Method(ref trait_m_sig, _) => {
                     if let Some(arg) = trait_m_sig.decl.inputs.get(if trait_number_args > 0 {
                         trait_number_args - 1
                     } else {
                         0
                     }) {
-                        Some(arg.pat.span)
+                        Some(arg.span)
                     } else {
                         trait_item_span
                     }
@@ -712,7 +698,7 @@ fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 } else {
                     0
                 }) {
-                    arg.pat.span
+                    arg.span
                 } else {
                     impl_m_span
                 }
@@ -839,7 +825,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             // Add a label to the Span containing just the type of the item
             let trait_c_node_id = tcx.map.as_local_node_id(trait_c.def_id).unwrap();
             let trait_c_span = match tcx.map.expect_trait_item(trait_c_node_id).node {
-                TraitItem_::ConstTraitItem(ref ty, _) => ty.span,
+                TraitItemKind::Const(ref ty, _) => ty.span,
                 _ => bug!("{:?} is not a trait const", trait_c),
             };
 
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 183a2a48ff523..c733c0856c6da 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -48,7 +48,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let i_n_tps = tcx.item_generics(def_id).types.len();
     if i_n_tps != n_tps {
         let span = match it.node {
-            hir::ForeignItemFn(_, ref generics) => generics.span,
+            hir::ForeignItemFn(_, _, ref generics) => generics.span,
             hir::ForeignItemStatic(..) => it.span
         };
 
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 86bfede87b333..04ec9292d1410 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -26,7 +26,6 @@ use syntax::ast;
 use errors::DiagnosticBuilder;
 use syntax_pos::Span;
 
-use rustc::hir::print as pprust;
 use rustc::hir;
 use rustc::infer::type_variable::TypeVariableOrigin;
 
@@ -266,7 +265,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 let msg = if let Some(callee) = rcvr_expr {
                     format!("{}; use overloaded call notation instead (e.g., `{}()`)",
                             msg,
-                            pprust::expr_to_string(callee))
+                            self.tcx.map.node_to_pretty_string(callee.id))
                 } else {
                     msg
                 };
@@ -463,6 +462,9 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
                 }
             }
 
+            fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+            }
+
             fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
             }
         }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a2dceed8d2653..7275fbd12036b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -122,7 +122,6 @@ use syntax_pos::{self, BytePos, Span, DUMMY_SP};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::{self, PatKind};
-use rustc::hir::print as pprust;
 use rustc::middle::lang_items;
 use rustc_back::slice;
 use rustc_const_eval::eval_length;
@@ -550,14 +549,25 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
 
     fn visit_ty(&mut self, t: &'tcx hir::Ty) {
         match t.node {
-            hir::TyArray(_, ref expr) => {
-                check_const_with_type(self.ccx, &expr, self.ccx.tcx.types.usize, expr.id);
+            hir::TyArray(_, length) => {
+                check_const_with_type(self.ccx, length, self.ccx.tcx.types.usize, length.node_id);
             }
             _ => {}
         }
 
         intravisit::walk_ty(self, t);
     }
+
+    fn visit_expr(&mut self, e: &'tcx hir::Expr) {
+        match e.node {
+            hir::ExprRepeat(_, count) => {
+                check_const_with_type(self.ccx, count, self.ccx.tcx.types.usize, count.node_id);
+            }
+            _ => {}
+        }
+
+        intravisit::walk_expr(self, e);
+    }
 }
 
 impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
@@ -565,6 +575,10 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
         check_item_body(self.ccx, i);
     }
 
+    fn visit_trait_item(&mut self, _item: &'tcx hir::TraitItem) {
+        // done as part of `visit_item` above
+    }
+
     fn visit_impl_item(&mut self, _item: &'tcx hir::ImplItem) {
         // done as part of `visit_item` above
     }
@@ -635,28 +649,28 @@ pub fn check_drop_impls(ccx: &CrateCtxt) -> CompileResult {
 
 fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                            decl: &'tcx hir::FnDecl,
-                           body_id: hir::ExprId,
+                           body_id: hir::BodyId,
                            fn_id: ast::NodeId,
                            span: Span) {
-    let body = ccx.tcx.map.expr(body_id);
+    let body = ccx.tcx.map.body(body_id);
 
     let raw_fty = ccx.tcx.item_type(ccx.tcx.map.local_def_id(fn_id));
     let fn_ty = match raw_fty.sty {
         ty::TyFnDef(.., f) => f,
-        _ => span_bug!(body.span, "check_bare_fn: function type expected")
+        _ => span_bug!(body.value.span, "check_bare_fn: function type expected")
     };
 
     check_abi(ccx, span, fn_ty.abi);
 
     ccx.inherited(fn_id).enter(|inh| {
         // Compute the fty from point of view of inside fn.
-        let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body_id.node_id());
+        let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body_id.node_id);
         let fn_sig =
             fn_ty.sig.subst(inh.tcx, &inh.parameter_environment.free_substs);
         let fn_sig =
             inh.tcx.liberate_late_bound_regions(fn_scope, &fn_sig);
         let fn_sig =
-            inh.normalize_associated_types_in(body.span, body_id.node_id(), &fn_sig);
+            inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
 
         let fcx = check_fn(&inh, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body);
 
@@ -666,8 +680,8 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         fcx.check_casts();
         fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
 
-        fcx.regionck_fn(fn_id, decl, body_id);
-        fcx.resolve_type_vars_in_fn(decl, body, fn_id);
+        fcx.regionck_fn(fn_id, body);
+        fcx.resolve_type_vars_in_body(body, fn_id);
     });
 }
 
@@ -736,32 +750,9 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
         intravisit::walk_pat(self, p);
     }
 
-    fn visit_block(&mut self, b: &'gcx hir::Block) {
-        // non-obvious: the `blk` variable maps to region lb, so
-        // we have to keep this up-to-date.  This
-        // is... unfortunate.  It'd be nice to not need this.
-        intravisit::walk_block(self, b);
-    }
-
-    // Since an expr occurs as part of the type fixed size arrays we
-    // need to record the type for that node
-    fn visit_ty(&mut self, t: &'gcx hir::Ty) {
-        match t.node {
-            hir::TyArray(ref ty, ref count_expr) => {
-                self.visit_ty(&ty);
-                self.fcx.check_expr_with_hint(&count_expr, self.fcx.tcx.types.usize);
-            }
-            hir::TyBareFn(ref function_declaration) => {
-                intravisit::walk_fn_decl_nopat(self, &function_declaration.decl);
-                walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
-            }
-            _ => intravisit::walk_ty(self, t)
-        }
-    }
-
     // Don't descend into the bodies of nested closures
     fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
-                _: hir::ExprId, _: Span, _: ast::NodeId) { }
+                _: hir::BodyId, _: Span, _: ast::NodeId) { }
 }
 
 /// Helper used by check_bare_fn and check_expr_fn. Does the grungy work of checking a function
@@ -776,7 +767,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
                             fn_sig: &ty::FnSig<'tcx>,
                             decl: &'gcx hir::FnDecl,
                             fn_id: ast::NodeId,
-                            body: &'gcx hir::Expr)
+                            body: &'gcx hir::Body)
                             -> FnCtxt<'a, 'gcx, 'tcx>
 {
     let mut fn_sig = fn_sig.clone();
@@ -785,7 +776,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
 
     // Create the function context.  This is either derived from scratch or,
     // in the case of function expressions, based on the outer context.
-    let mut fcx = FnCtxt::new(inherited, None, body.id);
+    let mut fcx = FnCtxt::new(inherited, None, body.value.id);
     let ret_ty = fn_sig.output();
     *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
 
@@ -794,36 +785,26 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty.unwrap(),
                                fn_sig.variadic);
 
-    {
-        let mut visit = GatherLocalsVisitor { fcx: &fcx, };
-
-        // Add formal parameters.
-        for (arg_ty, input) in fn_sig.inputs().iter().zip(&decl.inputs) {
-            // The type of the argument must be well-formed.
-            //
-            // NB -- this is now checked in wfcheck, but that
-            // currently only results in warnings, so we issue an
-            // old-style WF obligation here so that we still get the
-            // errors that we used to get.
-            fcx.register_old_wf_obligation(arg_ty, input.ty.span, traits::MiscObligation);
-
-            // Create type variables for each argument.
-            input.pat.each_binding(|_bm, pat_id, sp, _path| {
-                let var_ty = visit.assign(sp, pat_id, None);
-                fcx.require_type_is_sized(var_ty, sp, traits::VariableType(pat_id));
-            });
+    GatherLocalsVisitor { fcx: &fcx, }.visit_body(body);
 
-            // Check the pattern.
-            fcx.check_pat(&input.pat, arg_ty);
-            fcx.write_ty(input.id, arg_ty);
-        }
+    // Add formal parameters.
+    for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) {
+        // The type of the argument must be well-formed.
+        //
+        // NB -- this is now checked in wfcheck, but that
+        // currently only results in warnings, so we issue an
+        // old-style WF obligation here so that we still get the
+        // errors that we used to get.
+        fcx.register_old_wf_obligation(arg_ty, arg.pat.span, traits::MiscObligation);
 
-        visit.visit_expr(body);
+        // Check the pattern.
+        fcx.check_pat(&arg.pat, arg_ty);
+        fcx.write_ty(arg.id, arg_ty);
     }
 
     inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig);
 
-    fcx.check_expr_coercable_to_type(body, fcx.ret_ty.unwrap());
+    fcx.check_expr_coercable_to_type(&body.value, fcx.ret_ty.unwrap());
 
     fcx
 }
@@ -848,8 +829,8 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
     let _indenter = indenter();
     match it.node {
       // Consts can play a role in type-checking, so they are included here.
-      hir::ItemStatic(.., ref e) |
-      hir::ItemConst(_, ref e) => check_const(ccx, &e, it.id),
+      hir::ItemStatic(.., e) |
+      hir::ItemConst(_, e) => check_const(ccx, e, it.id),
       hir::ItemEnum(ref enum_definition, _) => {
         check_enum_variants(ccx,
                             it.span,
@@ -908,7 +889,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
                     err.emit();
                 }
 
-                if let hir::ForeignItemFn(ref fn_decl, _) = item.node {
+                if let hir::ForeignItemFn(ref fn_decl, _, _) = item.node {
                     require_c_abi_if_variadic(ccx.tcx, fn_decl, m.abi, item.span);
                 }
             }
@@ -933,8 +914,8 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
         for impl_item_ref in impl_item_refs {
             let impl_item = ccx.tcx.map.impl_item(impl_item_ref.id);
             match impl_item.node {
-                hir::ImplItemKind::Const(_, ref expr) => {
-                    check_const(ccx, &expr, impl_item.id)
+                hir::ImplItemKind::Const(_, expr) => {
+                    check_const(ccx, expr, impl_item.id)
                 }
                 hir::ImplItemKind::Method(ref sig, body_id) => {
                     check_bare_fn(ccx, &sig.decl, body_id, impl_item.id, impl_item.span);
@@ -945,18 +926,19 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
             }
         }
       }
-      hir::ItemTrait(.., ref trait_items) => {
-        for trait_item in trait_items {
+      hir::ItemTrait(.., ref trait_item_refs) => {
+        for trait_item_ref in trait_item_refs {
+            let trait_item = ccx.tcx.map.trait_item(trait_item_ref.id);
             match trait_item.node {
-                hir::ConstTraitItem(_, Some(ref expr)) => {
-                    check_const(ccx, &expr, trait_item.id)
+                hir::TraitItemKind::Const(_, Some(expr)) => {
+                    check_const(ccx, expr, trait_item.id)
                 }
-                hir::MethodTraitItem(ref sig, Some(body_id)) => {
+                hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body_id)) => {
                     check_bare_fn(ccx, &sig.decl, body_id, trait_item.id, trait_item.span);
                 }
-                hir::MethodTraitItem(_, None) |
-                hir::ConstTraitItem(_, None) |
-                hir::TypeTraitItem(..) => {
+                hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
+                hir::TraitItemKind::Const(_, None) |
+                hir::TraitItemKind::Type(..) => {
                     // Nothing to do.
                 }
             }
@@ -1122,7 +1104,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         compare_impl_method(ccx,
                                             &ty_impl_item,
                                             impl_item.span,
-                                            body_id.node_id(),
+                                            body_id.node_id,
                                             &ty_trait_item,
                                             impl_trait_ref,
                                             trait_span,
@@ -1132,7 +1114,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             compare_impl_method(ccx,
                                                 &ty_impl_item,
                                                 impl_item.span,
-                                                body_id.node_id(),
+                                                body_id.node_id,
                                                 &ty_trait_item,
                                                 impl_trait_ref,
                                                 trait_span,
@@ -1243,37 +1225,38 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
 /// Checks a constant with a given type.
 fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
-                                   expr: &'tcx hir::Expr,
+                                   body: hir::BodyId,
                                    expected_type: Ty<'tcx>,
                                    id: ast::NodeId) {
+    let body = ccx.tcx.map.body(body);
     ccx.inherited(id).enter(|inh| {
-        let fcx = FnCtxt::new(&inh, None, expr.id);
-        fcx.require_type_is_sized(expected_type, expr.span, traits::ConstSized);
+        let fcx = FnCtxt::new(&inh, None, body.value.id);
+        fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
 
         // Gather locals in statics (because of block expressions).
         // This is technically unnecessary because locals in static items are forbidden,
         // but prevents type checking from blowing up before const checking can properly
         // emit an error.
-        GatherLocalsVisitor { fcx: &fcx }.visit_expr(expr);
+        GatherLocalsVisitor { fcx: &fcx }.visit_body(body);
 
-        fcx.check_expr_coercable_to_type(expr, expected_type);
+        fcx.check_expr_coercable_to_type(&body.value, expected_type);
 
         fcx.select_all_obligations_and_apply_defaults();
-        fcx.closure_analyze(expr);
+        fcx.closure_analyze(body);
         fcx.select_obligations_where_possible();
         fcx.check_casts();
         fcx.select_all_obligations_or_error();
 
-        fcx.regionck_expr(expr);
-        fcx.resolve_type_vars_in_expr(expr, id);
+        fcx.regionck_expr(body);
+        fcx.resolve_type_vars_in_body(body, id);
     });
 }
 
 fn check_const<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>,
-                         expr: &'tcx hir::Expr,
+                         body: hir::BodyId,
                          id: ast::NodeId) {
     let decl_ty = ccx.tcx.item_type(ccx.tcx.map.local_def_id(id));
-    check_const_with_type(ccx, expr, decl_ty, id);
+    check_const_with_type(ccx, body, decl_ty, id);
 }
 
 /// Checks whether a type can be represented in memory. In particular, it
@@ -1348,8 +1331,8 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
 
     let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx);
     for v in vs {
-        if let Some(ref e) = v.node.disr_expr {
-            check_const_with_type(ccx, e, repr_type_ty, e.id);
+        if let Some(e) = v.node.disr_expr {
+            check_const_with_type(ccx, e, repr_type_ty, e.node_id);
         }
     }
 
@@ -1365,11 +1348,11 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
             let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap();
             let variant_i = ccx.tcx.map.expect_variant(variant_i_node_id);
             let i_span = match variant_i.node.disr_expr {
-                Some(ref expr) => expr.span,
+                Some(expr) => ccx.tcx.map.span(expr.node_id),
                 None => ccx.tcx.map.span(variant_i_node_id)
             };
             let span = match v.node.disr_expr {
-                Some(ref expr) => expr.span,
+                Some(expr) => ccx.tcx.map.span(expr.node_id),
                 None => v.span
             };
             struct_span_err!(ccx.tcx.sess, span, E0081,
@@ -1643,12 +1626,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         match self.locals.borrow().get(&nid) {
             Some(&t) => t,
             None => {
-                struct_span_err!(self.tcx.sess, span, E0513,
-                                 "no type for local variable {}",
-                                 self.tcx.map.node_to_string(nid))
-                    .span_label(span, &"no type for variable")
-                    .emit();
-                self.tcx.types.err
+                span_bug!(span, "no type for local variable {}",
+                          self.tcx.map.node_to_string(nid));
             }
         }
     }
@@ -3065,7 +3044,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
                 ty::TyRawPtr(..) => {
                     err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \
-                                      `(*{0}).{1}`", pprust::expr_to_string(base), field.node));
+                                      `(*{0}).{1}`",
+                                      self.tcx.map.node_to_pretty_string(base.id),
+                                      field.node));
                 }
                 _ => {}
             }
@@ -3479,11 +3460,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.diverges.set(self.diverges.get() | old_diverges);
         self.has_errors.set(self.has_errors.get() | old_has_errors);
 
-        debug!("type of expr({}) {} is...", expr.id,
-               pprust::expr_to_string(expr));
-        debug!("... {:?}, expected is {:?}",
-               ty,
-               expected);
+        debug!("type of {} is...", self.tcx.map.node_to_string(expr.id));
+        debug!("... {:?}, expected is {:?}", ty, expected);
 
         // Add adjustments to !-expressions
         if ty.is_never() {
@@ -3821,10 +3799,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               self.check_method_call(expr, name, args, &tps[..], expected, lvalue_pref)
           }
           hir::ExprCast(ref e, ref t) => {
-            if let hir::TyArray(_, ref count_expr) = t.node {
-                self.check_expr_with_hint(&count_expr, tcx.types.usize);
-            }
-
             // Find the type of `e`. Supply hints based on the type we are casting to,
             // if appropriate.
             let t_cast = self.to_ty(t);
@@ -3886,9 +3860,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
             tcx.mk_array(unified, args.len())
           }
-          hir::ExprRepeat(ref element, ref count_expr) => {
-            self.check_expr_has_type(&count_expr, tcx.types.usize);
-            let count = eval_length(self.tcx.global_tcx(), &count_expr, "repeat count")
+          hir::ExprRepeat(ref element, count) => {
+            let count_expr = &tcx.map.body(count).value;
+            let count = eval_length(self.tcx.global_tcx(), count_expr, "repeat count")
                   .unwrap_or(0);
 
             let uty = match expected {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index eb08e70d4c3e4..bd63eb6ad25ef 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -113,12 +113,13 @@ macro_rules! ignore_err {
 // PUBLIC ENTRY POINTS
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    pub fn regionck_expr(&self, e: &'gcx hir::Expr) {
-        let mut rcx = RegionCtxt::new(self, RepeatingScope(e.id), e.id, Subject(e.id));
+    pub fn regionck_expr(&self, body: &'gcx hir::Body) {
+        let id = body.value.id;
+        let mut rcx = RegionCtxt::new(self, RepeatingScope(id), id, Subject(id));
         if self.err_count_since_creation() == 0 {
             // regionck assumes typeck succeeded
-            rcx.visit_expr(e);
-            rcx.visit_region_obligations(e.id);
+            rcx.visit_body(body);
+            rcx.visit_region_obligations(id);
         }
         rcx.resolve_regions_and_report_errors();
     }
@@ -140,15 +141,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     pub fn regionck_fn(&self,
                        fn_id: ast::NodeId,
-                       decl: &hir::FnDecl,
-                       body_id: hir::ExprId) {
+                       body: &'gcx hir::Body) {
         debug!("regionck_fn(id={})", fn_id);
-        let node_id = body_id.node_id();
+        let node_id = body.value.id;
         let mut rcx = RegionCtxt::new(self, RepeatingScope(node_id), node_id, Subject(fn_id));
 
         if self.err_count_since_creation() == 0 {
             // regionck assumes typeck succeeded
-            rcx.visit_fn_body(fn_id, decl, body_id, self.tcx.map.span(fn_id));
+            rcx.visit_fn_body(fn_id, body, self.tcx.map.span(fn_id));
         }
 
         rcx.free_region_map.relate_free_regions_from_predicates(
@@ -267,15 +267,16 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
     fn visit_fn_body(&mut self,
                      id: ast::NodeId, // the id of the fn itself
-                     fn_decl: &hir::FnDecl,
-                     body_id: hir::ExprId,
+                     body: &'gcx hir::Body,
                      span: Span)
     {
         // When we enter a function, we can derive
         debug!("visit_fn_body(id={})", id);
 
+        let body_id = body.id();
+
         let call_site = self.tcx.region_maps.lookup_code_extent(
-            region::CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id() });
+            region::CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id });
         let old_call_site_scope = self.set_call_site_scope(Some(call_site));
 
         let fn_sig = {
@@ -298,20 +299,18 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         let fn_sig_tys: Vec<_> =
             fn_sig.inputs().iter().cloned().chain(Some(fn_sig.output())).collect();
 
-        let old_body_id = self.set_body_id(body_id.node_id());
-        self.relate_free_regions(&fn_sig_tys[..], body_id.node_id(), span);
-        self.link_fn_args(self.tcx.region_maps.node_extent(body_id.node_id()),
-                          &fn_decl.inputs[..]);
-        let body = self.tcx.map.expr(body_id);
-        self.visit_expr(body);
-        self.visit_region_obligations(body_id.node_id());
+        let old_body_id = self.set_body_id(body_id.node_id);
+        self.relate_free_regions(&fn_sig_tys[..], body_id.node_id, span);
+        self.link_fn_args(self.tcx.region_maps.node_extent(body_id.node_id), &body.arguments);
+        self.visit_body(body);
+        self.visit_region_obligations(body_id.node_id);
 
         let call_site_scope = self.call_site_scope.unwrap();
-        debug!("visit_fn_body body.id {} call_site_scope: {:?}",
-               body.id, call_site_scope);
+        debug!("visit_fn_body body.id {:?} call_site_scope: {:?}",
+               body.id(), call_site_scope);
         let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope));
         self.type_of_node_must_outlive(infer::CallReturn(span),
-                                       body_id.node_id(),
+                                       body_id.node_id,
                                        call_site_region);
 
         self.region_bound_pairs.truncate(old_region_bounds_pairs_len);
@@ -478,12 +477,13 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
     // regions, until regionck, as described in #3238.
 
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
-        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+        NestedVisitorMap::None
     }
 
-    fn visit_fn(&mut self, _fk: intravisit::FnKind<'gcx>, fd: &'gcx hir::FnDecl,
-                b: hir::ExprId, span: Span, id: ast::NodeId) {
-        self.visit_fn_body(id, fd, b, span)
+    fn visit_fn(&mut self, _fk: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
+                b: hir::BodyId, span: Span, id: ast::NodeId) {
+        let body = self.tcx.map.body(b);
+        self.visit_fn_body(id, body, span)
     }
 
     //visit_pat: visit_pat, // (..) see above
@@ -826,8 +826,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
     fn check_expr_fn_block(&mut self,
                            expr: &'gcx hir::Expr,
-                           body_id: hir::ExprId) {
-        let repeating_scope = self.set_repeating_scope(body_id.node_id());
+                           body_id: hir::BodyId) {
+        let repeating_scope = self.set_repeating_scope(body_id.node_id);
         intravisit::walk_expr(self, expr);
         self.set_repeating_scope(repeating_scope);
     }
@@ -1113,7 +1113,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         for arg in args {
             let arg_ty = self.node_ty(arg.id);
             let re_scope = self.tcx.mk_region(ty::ReScope(body_scope));
-            let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty);
+            let arg_cmt = mc.cat_rvalue(arg.id, arg.pat.span, re_scope, arg_ty);
             debug!("arg_ty={:?} arg_cmt={:?} arg={:?}",
                    arg_ty,
                    arg_cmt,
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index 63d20416bded5..5d927a503a116 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -57,12 +57,12 @@ use rustc::util::nodemap::NodeMap;
 // PUBLIC ENTRY POINTS
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    pub fn closure_analyze(&self, body: &'gcx hir::Expr) {
+    pub fn closure_analyze(&self, body: &'gcx hir::Body) {
         let mut seed = SeedBorrowKind::new(self);
-        seed.visit_expr(body);
+        seed.visit_body(body);
 
         let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds);
-        adjust.visit_expr(body);
+        adjust.visit_body(body);
 
         // it's our job to process these.
         assert!(self.deferred_call_resolutions.borrow().is_empty());
@@ -79,13 +79,15 @@ struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 
 impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
-        NestedVisitorMap::OnlyBodies(&self.fcx.tcx.map)
+        NestedVisitorMap::None
     }
 
     fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
         match expr.node {
             hir::ExprClosure(cc, _, body_id, _) => {
-                self.check_closure(expr, cc, body_id);
+                let body = self.fcx.tcx.map.body(body_id);
+                self.visit_body(body);
+                self.check_closure(expr, cc);
             }
 
             _ => { }
@@ -102,8 +104,7 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
 
     fn check_closure(&mut self,
                      expr: &hir::Expr,
-                     capture_clause: hir::CaptureClause,
-                     _body_id: hir::ExprId)
+                     capture_clause: hir::CaptureClause)
     {
         let closure_def_id = self.fcx.tcx.map.local_def_id(expr.id);
         if !self.fcx.tables.borrow().closure_kinds.contains_key(&closure_def_id) {
@@ -156,23 +157,21 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
     fn analyze_closure(&mut self,
                        id: ast::NodeId,
                        span: Span,
-                       decl: &hir::FnDecl,
-                       body_id: hir::ExprId) {
+                       body: &hir::Body) {
         /*!
          * Analysis starting point.
          */
 
-        debug!("analyze_closure(id={:?}, body.id={:?})", id, body_id);
+        debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id());
 
         {
-            let body = self.fcx.tcx.map.expr(body_id);
             let mut euv =
                 euv::ExprUseVisitor::with_options(self,
                                                   self.fcx,
                                                   mc::MemCategorizationOptions {
                                                       during_closure_kind_inference: true
                                                   });
-            euv.walk_fn(decl, body);
+            euv.consume_body(body);
         }
 
         // Now that we've analyzed the closure, we know how each
@@ -491,18 +490,21 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
 
 impl<'a, 'gcx, 'tcx> Visitor<'gcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
-        NestedVisitorMap::OnlyBodies(&self.fcx.tcx.map)
+        NestedVisitorMap::None
     }
 
     fn visit_fn(&mut self,
                 fn_kind: intravisit::FnKind<'gcx>,
                 decl: &'gcx hir::FnDecl,
-                body: hir::ExprId,
+                body: hir::BodyId,
                 span: Span,
                 id: ast::NodeId)
     {
         intravisit::walk_fn(self, fn_kind, decl, body, span, id);
-        self.analyze_closure(id, span, decl, body);
+
+        let body = self.fcx.tcx.map.body(body);
+        self.visit_body(body);
+        self.analyze_closure(id, span, body);
     }
 }
 
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index ffdb56753fdc1..c80db7fa4d0e0 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -159,10 +159,10 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
         }
     }
 
-    fn check_trait_or_impl_item(&mut self,
-                                item_id: ast::NodeId,
-                                span: Span,
-                                sig_if_method: Option<&hir::MethodSig>) {
+    fn check_associated_item(&mut self,
+                             item_id: ast::NodeId,
+                             span: Span,
+                             sig_if_method: Option<&hir::MethodSig>) {
         let code = self.code.clone();
         self.for_id(item_id, span).with_fcx(|fcx, this| {
             let free_substs = &fcx.parameter_environment.free_substs;
@@ -337,7 +337,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
 
     fn check_item_fn(&mut self,
                      item: &hir::Item,
-                     body_id: hir::ExprId)
+                     body_id: hir::BodyId)
     {
         self.for_item(item).with_fcx(|fcx, this| {
             let free_substs = &fcx.parameter_environment.free_substs;
@@ -354,7 +354,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
             let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs);
 
             let mut implied_bounds = vec![];
-            let free_id_outlive = fcx.tcx.region_maps.call_site_extent(item.id, body_id.node_id());
+            let free_id_outlive = fcx.tcx.region_maps.call_site_extent(item.id, body_id.node_id);
             this.check_fn_or_method(fcx, item.span, bare_fn_ty, &predicates,
                                     free_id_outlive, &mut implied_bounds);
             implied_bounds
@@ -478,7 +478,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
             return;
         }
 
-        let span = method_sig.decl.inputs[0].pat.span;
+        let span = method_sig.decl.inputs[0].span;
 
         let free_substs = &fcx.parameter_environment.free_substs;
         let method_ty = fcx.tcx.item_type(method.def_id);
@@ -607,10 +607,10 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
     fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) {
         debug!("visit_trait_item: {:?}", trait_item);
         let method_sig = match trait_item.node {
-            hir::TraitItem_::MethodTraitItem(ref sig, _) => Some(sig),
+            hir::TraitItemKind::Method(ref sig, _) => Some(sig),
             _ => None
         };
-        self.check_trait_or_impl_item(trait_item.id, trait_item.span, method_sig);
+        self.check_associated_item(trait_item.id, trait_item.span, method_sig);
         intravisit::walk_trait_item(self, trait_item)
     }
 
@@ -620,7 +620,7 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
             hir::ImplItemKind::Method(ref sig, _) => Some(sig),
             _ => None
         };
-        self.check_trait_or_impl_item(impl_item.id, impl_item.span, method_sig);
+        self.check_associated_item(impl_item.id, impl_item.span, method_sig);
         intravisit::walk_impl_item(self, impl_item)
     }
 }
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 56de75995fd2e..9a2bfbf715af9 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -26,42 +26,22 @@ use std::cell::Cell;
 use syntax::ast;
 use syntax_pos::Span;
 
-use rustc::hir::print::pat_to_string;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
-use rustc::hir::{self, PatKind};
+use rustc::hir;
 
 ///////////////////////////////////////////////////////////////////////////
-// Entry point functions
+// Entry point
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    pub fn resolve_type_vars_in_expr(&self, e: &'gcx hir::Expr, item_id: ast::NodeId) {
+    pub fn resolve_type_vars_in_body(&self,
+                                     body: &'gcx hir::Body,
+                                     item_id: ast::NodeId) {
         assert_eq!(self.writeback_errors.get(), false);
         let mut wbcx = WritebackCx::new(self);
-        wbcx.visit_expr(e);
-        wbcx.visit_upvar_borrow_map();
-        wbcx.visit_closures();
-        wbcx.visit_liberated_fn_sigs();
-        wbcx.visit_fru_field_types();
-        wbcx.visit_deferred_obligations(item_id);
-        wbcx.visit_type_nodes();
-    }
-
-    pub fn resolve_type_vars_in_fn(&self,
-                                   decl: &'gcx hir::FnDecl,
-                                   body: &'gcx hir::Expr,
-                                   item_id: ast::NodeId) {
-        assert_eq!(self.writeback_errors.get(), false);
-        let mut wbcx = WritebackCx::new(self);
-        wbcx.visit_expr(body);
-        for arg in &decl.inputs {
+        for arg in &body.arguments {
             wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id);
-            wbcx.visit_pat(&arg.pat);
-
-            // Privacy needs the type for the whole pattern, not just each binding
-            if let PatKind::Binding(..) = arg.pat.node {} else {
-                wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.pat.id);
-            }
         }
+        wbcx.visit_body(body);
         wbcx.visit_upvar_borrow_map();
         wbcx.visit_closures();
         wbcx.visit_liberated_fn_sigs();
@@ -188,7 +168,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
 
 impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
-        NestedVisitorMap::OnlyBodies(&self.fcx.tcx.map)
+        NestedVisitorMap::None
     }
 
     fn visit_stmt(&mut self, s: &'gcx hir::Stmt) {
@@ -211,10 +191,13 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
         self.visit_method_map_entry(ResolvingExpr(e.span),
                                     MethodCall::expr(e.id));
 
-        if let hir::ExprClosure(_, ref decl, ..) = e.node {
-            for input in &decl.inputs {
-                self.visit_node_id(ResolvingExpr(e.span), input.id);
+        if let hir::ExprClosure(_, _, body, _) = e.node {
+            let body = self.fcx.tcx.map.body(body);
+            for arg in &body.arguments {
+                self.visit_node_id(ResolvingExpr(e.span), arg.id);
             }
+
+            self.visit_body(body);
         }
 
         intravisit::walk_expr(self, e);
@@ -237,7 +220,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
         self.visit_node_id(ResolvingPattern(p.span), p.id);
 
         debug!("Type for pattern binding {} (id {}) resolved to {:?}",
-               pat_to_string(p),
+               self.tcx().map.node_to_pretty_string(p.id),
                p.id,
                self.tcx().tables().node_id_to_type(p.id));
 
@@ -254,20 +237,6 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
         self.write_ty_to_tcx(l.id, var_ty);
         intravisit::walk_local(self, l);
     }
-
-    fn visit_ty(&mut self, t: &'gcx hir::Ty) {
-        match t.node {
-            hir::TyArray(ref ty, ref count_expr) => {
-                self.visit_ty(&ty);
-                self.write_ty_to_tcx(count_expr.id, self.tcx().types.usize);
-            }
-            hir::TyBareFn(ref function_declaration) => {
-                intravisit::walk_fn_decl_nopat(self, &function_declaration.decl);
-                walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
-            }
-            _ => intravisit::walk_ty(self, t)
-        }
-    }
 }
 
 impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs
index 0034a85f8e29e..cd9453770a6ab 100644
--- a/src/librustc_typeck/check_unused.rs
+++ b/src/librustc_typeck/check_unused.rs
@@ -50,6 +50,9 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> {
         }
     }
 
+    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+    }
+
     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
     }
 }
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 0e5a16987c12e..3bbe5aa1fef37 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -58,6 +58,9 @@ impl<'a, 'gcx, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCheckVisitor<'a, 'gcx,
         }
     }
 
+    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+    }
+
     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
     }
 }
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index 2e8206ec95967..bc1ead07c0ea7 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -67,13 +67,15 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
             }
         }
     }
+}
 
+impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
     /// Checks exactly one impl for orphan rules and other such
     /// restrictions.  In this fn, it can happen that multiple errors
     /// apply to a specific impl, so just return after reporting one
     /// to prevent inundating the user with a bunch of similar error
     /// reports.
-    fn check_item(&self, item: &hir::Item) {
+    fn visit_item(&mut self, item: &hir::Item) {
         let def_id = self.tcx.map.local_def_id(item.id);
         match item.node {
             hir::ItemImpl(.., None, ref ty, _) => {
@@ -368,7 +370,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
                                       the crate they're defined in; define a new trait instead")
                         .span_label(item_trait_ref.path.span,
                                     &format!("`{}` trait not defined in this crate",
-                                             item_trait_ref.path))
+                            self.tcx.map.node_to_pretty_string(item_trait_ref.ref_id)))
                         .emit();
                     return;
                 }
@@ -378,11 +380,8 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
             }
         }
     }
-}
 
-impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
-    fn visit_item(&mut self, item: &hir::Item) {
-        self.check_item(item);
+    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
     }
 
     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index 815811675a54b..a09bdf0533a15 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -205,6 +205,9 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
         }
     }
 
+    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+    }
+
     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
     }
 }
diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs
index 6d5de8f250655..c4c7c699f65f6 100644
--- a/src/librustc_typeck/coherence/unsafety.rs
+++ b/src/librustc_typeck/coherence/unsafety.rs
@@ -107,6 +107,9 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> {
         }
     }
 
+    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+    }
+
     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
     }
 }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index fba77d171797e..fd51b38e1b557 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -82,7 +82,7 @@ use syntax::{abi, ast, attr};
 use syntax::symbol::{Symbol, keywords};
 use syntax_pos::Span;
 
-use rustc::hir::{self, map as hir_map, print as pprust};
+use rustc::hir::{self, map as hir_map};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
@@ -204,6 +204,13 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
         intravisit::walk_ty(self, ty);
     }
 
+    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
+        self.with_collect_item_sig(trait_item.id, || {
+            convert_trait_item(self.ccx, trait_item)
+        });
+        intravisit::walk_trait_item(self, trait_item);
+    }
+
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
         self.with_collect_item_sig(impl_item.id, || {
             convert_impl_item(self.ccx, impl_item)
@@ -633,7 +640,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             id: ast::NodeId,
                             sig: &hir::MethodSig,
                             untransformed_rcvr_ty: Ty<'tcx>,
-                            rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) {
+                            body: Option<hir::BodyId>,
+                            rcvr_ty_predicates: &ty::GenericPredicates<'tcx>,) {
     let def_id = ccx.tcx.map.local_def_id(id);
     let ty_generics = generics_of_def_id(ccx, def_id);
 
@@ -644,8 +652,14 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         ImplContainer(_) => Some(AnonTypeScope::new(def_id)),
         TraitContainer(_) => None
     };
+    let assoc_item = ccx.tcx.associated_item(def_id);
+    let self_value_ty = if assoc_item.method_has_self_argument {
+        Some(untransformed_rcvr_ty)
+    } else {
+        None
+    };
     let fty = AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
-                                    sig, untransformed_rcvr_ty, anon_scope);
+                                    sig, self_value_ty, body, anon_scope);
 
     let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
                                 ccx.tcx.map.span(id), def_id);
@@ -785,56 +799,12 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
             tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone());
         },
-        hir::ItemTrait(.., ref trait_items) => {
+        hir::ItemTrait(..) => {
             generics_of_def_id(ccx, def_id);
             trait_def_of_item(ccx, it);
             let _: Result<(), ErrorReported> = // any error is already reported, can ignore
                 ccx.ensure_super_predicates(it.span, def_id);
             convert_trait_predicates(ccx, it);
-            let trait_predicates = tcx.item_predicates(def_id);
-
-            debug!("convert: trait_bounds={:?}", trait_predicates);
-
-            // FIXME: is the ordering here important? I think it is.
-            let container = TraitContainer(def_id);
-
-            // Convert all the associated constants.
-            for trait_item in trait_items {
-                if let hir::ConstTraitItem(ref ty, _) = trait_item.node {
-                    let const_def_id = ccx.tcx.map.local_def_id(trait_item.id);
-                    generics_of_def_id(ccx, const_def_id);
-                    let ty = ccx.icx(&trait_predicates)
-                        .to_ty(&ExplicitRscope, ty);
-                    tcx.item_types.borrow_mut().insert(const_def_id, ty);
-                    convert_associated_const(ccx, container, trait_item.id, ty)
-                }
-            }
-
-            // Convert all the associated types.
-            for trait_item in trait_items {
-                if let hir::TypeTraitItem(_, ref opt_ty) = trait_item.node {
-                    let type_def_id = ccx.tcx.map.local_def_id(trait_item.id);
-                    generics_of_def_id(ccx, type_def_id);
-
-                    let typ = opt_ty.as_ref().map({
-                        |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
-                    });
-
-                    convert_associated_type(ccx, container, trait_item.id, typ);
-                }
-            }
-
-            // Convert all the methods
-            for trait_item in trait_items {
-                if let hir::MethodTraitItem(ref sig, _) = trait_item.node {
-                    convert_method(ccx,
-                                   container,
-                                   trait_item.id,
-                                   sig,
-                                   tcx.mk_self_type(),
-                                   &trait_predicates);
-                }
-            }
         },
         hir::ItemStruct(ref struct_def, _) |
         hir::ItemUnion(ref struct_def, _) => {
@@ -866,6 +836,48 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
     }
 }
 
+fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) {
+    let tcx = ccx.tcx;
+
+    // we can lookup details about the trait because items are visited
+    // before trait-items
+    let trait_def_id = tcx.map.get_parent_did(trait_item.id);
+    let trait_predicates = tcx.item_predicates(trait_def_id);
+
+    match trait_item.node {
+        hir::TraitItemKind::Const(ref ty, _) => {
+            let const_def_id = ccx.tcx.map.local_def_id(trait_item.id);
+            generics_of_def_id(ccx, const_def_id);
+            let ty = ccx.icx(&trait_predicates)
+                        .to_ty(&ExplicitRscope, &ty);
+            tcx.item_types.borrow_mut().insert(const_def_id, ty);
+            convert_associated_const(ccx, TraitContainer(trait_def_id),
+                                     trait_item.id, ty);
+        }
+
+        hir::TraitItemKind::Type(_, ref opt_ty) => {
+            let type_def_id = ccx.tcx.map.local_def_id(trait_item.id);
+            generics_of_def_id(ccx, type_def_id);
+
+            let typ = opt_ty.as_ref().map({
+                |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
+            });
+
+            convert_associated_type(ccx, TraitContainer(trait_def_id), trait_item.id, typ);
+        }
+
+        hir::TraitItemKind::Method(ref sig, ref method) => {
+            let body = match *method {
+                hir::TraitMethod::Required(_) => None,
+                hir::TraitMethod::Provided(body) => Some(body)
+            };
+            convert_method(ccx, TraitContainer(trait_def_id),
+                           trait_item.id, sig, tcx.mk_self_type(),
+                           body, &trait_predicates);
+        }
+    }
+}
+
 fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
     let tcx = ccx.tcx;
 
@@ -901,10 +913,10 @@ fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
             convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ));
         }
 
-        hir::ImplItemKind::Method(ref sig, _) => {
+        hir::ImplItemKind::Method(ref sig, body) => {
             convert_method(ccx, ImplContainer(impl_def_id),
                            impl_item.id, sig, impl_self_ty,
-                           &impl_predicates);
+                           Some(body), &impl_predicates);
         }
     }
 }
@@ -1029,7 +1041,7 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr)
                           -> Option<ty::Disr> {
-        debug!("disr expr, checking {}", pprust::expr_to_string(e));
+        debug!("disr expr, checking {}", ccx.tcx.map.node_to_pretty_string(e.id));
 
         let ty_hint = repr_ty.to_ty(ccx.tcx);
         let print_err = |cv: ConstVal| {
@@ -1088,7 +1100,8 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let mut prev_disr = None::<ty::Disr>;
     let variants = def.variants.iter().map(|v| {
         let wrapped_disr = prev_disr.map_or(initial, |d| d.wrap_incr());
-        let disr = if let Some(ref e) = v.node.disr_expr {
+        let disr = if let Some(e) = v.node.disr_expr {
+            let e = &tcx.map.body(e).value;
             evaluate_disr_expr(ccx, repr_type, e)
         } else if let Some(disr) = repr_type.disr_incr(tcx, prev_disr) {
             Some(disr)
@@ -1290,12 +1303,13 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item)
                                                  ast_generics: &hir::Generics,
                                                  trait_predicates: &ty::GenericPredicates<'tcx>,
                                                  self_trait_ref: ty::TraitRef<'tcx>,
-                                                 trait_items: &[hir::TraitItem])
+                                                 trait_item_refs: &[hir::TraitItemRef])
                                                  -> Vec<ty::Predicate<'tcx>>
     {
-        trait_items.iter().flat_map(|trait_item| {
+        trait_item_refs.iter().flat_map(|trait_item_ref| {
+            let trait_item = ccx.tcx.map.trait_item(trait_item_ref.id);
             let bounds = match trait_item.node {
-                hir::TypeTraitItem(ref bounds, _) => bounds,
+                hir::TraitItemKind::Type(ref bounds, _) => bounds,
                 _ => {
                     return vec![].into_iter();
                 }
@@ -1363,7 +1377,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         let ast_generics = match node {
             NodeTraitItem(item) => {
                 match item.node {
-                    MethodTraitItem(ref sig, _) => &sig.generics,
+                    TraitItemKind::Method(ref sig, _) => &sig.generics,
                     _ => &no_generics
                 }
             }
@@ -1420,7 +1434,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             NodeForeignItem(item) => {
                 match item.node {
                     ForeignItemStatic(..) => &no_generics,
-                    ForeignItemFn(_, ref generics) => generics
+                    ForeignItemFn(_, _, ref generics) => generics
                 }
             }
 
@@ -1521,9 +1535,9 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                     ItemStatic(ref t, ..) | ItemConst(ref t, _) => {
                         ccx.icx(&()).to_ty(&StaticRscope::new(&ccx.tcx), &t)
                     }
-                    ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
+                    ItemFn(ref decl, unsafety, _, abi, ref generics, body) => {
                         let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl,
-                                                          Some(AnonTypeScope::new(def_id)));
+                                                          body, Some(AnonTypeScope::new(def_id)));
                         let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
                         ccx.tcx.mk_fn_def(def_id, substs, tofd)
                     }
@@ -1563,7 +1577,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 let abi = ccx.tcx.map.get_foreign_abi(node_id);
 
                 match foreign_item.node {
-                    ForeignItemFn(ref fn_decl, ref generics) => {
+                    ForeignItemFn(ref fn_decl, _, ref generics) => {
                         compute_type_of_foreign_fn_decl(
                             ccx, ccx.tcx.map.local_def_id(foreign_item.id),
                             fn_decl, generics, abi)
@@ -1628,7 +1642,7 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     let no_generics = hir::Generics::empty();
     let generics = match it.node {
-        hir::ForeignItemFn(_, ref generics) => generics,
+        hir::ForeignItemFn(_, _, ref generics) => generics,
         hir::ForeignItemStatic(..) => &no_generics
     };
 
@@ -2058,13 +2072,13 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>(
                 ccx.tcx.sess.struct_span_err(ast_ty.span,
                               &format!("use of SIMD type `{}` in FFI is highly experimental and \
                                         may result in invalid code",
-                                       pprust::ty_to_string(ast_ty)))
+                                       ccx.tcx.map.node_to_pretty_string(ast_ty.id)))
                     .help("add #![feature(simd_ffi)] to the crate attributes to enable")
                     .emit();
             }
         };
         for (input, ty) in decl.inputs.iter().zip(&input_tys) {
-            check(&input.ty, ty)
+            check(&input, ty)
         }
         if let hir::Return(ref ty) = decl.output {
             check(&ty, output)
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index cea3ad43a95b8..d3b671f2a4d6e 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -3866,45 +3866,6 @@ extern "platform-intrinsic" {
 ```
 "##,
 
-E0513: r##"
-The type of the variable couldn't be found out.
-
-Erroneous code example:
-
-```compile_fail,E0513
-use std::mem;
-
-unsafe {
-    let size = mem::size_of::<u32>();
-    mem::transmute_copy::<u32, [u8; size]>(&8_8);
-    // error: no type for local variable
-}
-```
-
-To fix this error, please use a constant size instead of `size`. To make
-this error more obvious, you could run:
-
-```compile_fail,E0080
-use std::mem;
-
-unsafe {
-    mem::transmute_copy::<u32, [u8; mem::size_of::<u32>()]>(&8_8);
-    // error: constant evaluation error
-}
-```
-
-So now, you can fix your code by setting the size directly:
-
-```
-use std::mem;
-
-unsafe {
-    mem::transmute_copy::<u32, [u8; 4]>(&8_8);
-    // `u32` is 4 bytes so we replace the `mem::size_of` call with its size
-}
-```
-"##,
-
 E0516: r##"
 The `typeof` keyword is currently reserved but unimplemented.
 Erroneous code example:
diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs
index 9f5b73d9b3075..ce495e6fb4cd8 100644
--- a/src/librustc_typeck/impl_wf_check.rs
+++ b/src/librustc_typeck/impl_wf_check.rs
@@ -87,6 +87,8 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for ImplWfCheck<'a, 'tcx> {
         }
     }
 
+    fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem) { }
+
     fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { }
 }
 
diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs
index 131ecfc6e0c78..3f5e443a20a68 100644
--- a/src/librustc_typeck/rscope.rs
+++ b/src/librustc_typeck/rscope.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::ty;
 use rustc::ty::subst::Substs;
@@ -19,7 +20,10 @@ use syntax_pos::Span;
 
 #[derive(Clone)]
 pub struct ElisionFailureInfo {
-    pub name: String,
+    /// Where we can find the argument pattern.
+    pub parent: Option<hir::BodyId>,
+    /// The index of the argument in the original definition.
+    pub index: usize,
     pub lifetime_count: usize,
     pub have_bound_regions: bool
 }
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 39f996ee62b54..507079a4f874c 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -120,6 +120,9 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
         }
     }
 
+    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+    }
+
     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
     }
 }
diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs
index 851cfcd87231f..d4d3edbcb126e 100644
--- a/src/librustc_typeck/variance/terms.rs
+++ b/src/librustc_typeck/variance/terms.rs
@@ -258,6 +258,9 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> {
         }
     }
 
+    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+    }
+
     fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
     }
 }
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 94e9fdbfc3e2c..cba5e1ba6f318 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -10,6 +10,8 @@
 
 //! Support for inlining external documentation into the current AST.
 
+use std::collections::BTreeMap;
+use std::io;
 use std::iter::once;
 
 use syntax::ast;
@@ -17,12 +19,9 @@ use rustc::hir;
 
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
-use rustc::hir::print as pprust;
 use rustc::ty;
 use rustc::util::nodemap::FxHashSet;
 
-use rustc_const_eval::lookup_const_by_id;
-
 use core::{DocContext, DocAccessLevels};
 use doctree;
 use clean::{self, GetDefId};
@@ -345,8 +344,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
         match item.kind {
             ty::AssociatedKind::Const => {
                 let default = if item.defaultness.has_value() {
-                    Some(pprust::expr_to_string(
-                        lookup_const_by_id(tcx, item.def_id, None).unwrap().0))
+                    Some(print_inlined_const(cx, item.def_id))
                 } else {
                     None
                 };
@@ -476,17 +474,33 @@ fn build_module(cx: &DocContext, did: DefId) -> clean::Module {
     }
 }
 
-fn build_const(cx: &DocContext, did: DefId) -> clean::Constant {
-    let (expr, ty) = lookup_const_by_id(cx.tcx, did, None).unwrap_or_else(|| {
-        panic!("expected lookup_const_by_id to succeed for {:?}", did);
-    });
-    debug!("converting constant expr {:?} to snippet", expr);
-    let sn = pprust::expr_to_string(expr);
-    debug!("got snippet {}", sn);
+struct InlinedConst {
+    nested_bodies: BTreeMap<hir::BodyId, hir::Body>
+}
+
+impl hir::print::PpAnn for InlinedConst {
+    fn nested(&self, state: &mut hir::print::State, nested: hir::print::Nested)
+              -> io::Result<()> {
+        if let hir::print::Nested::Body(body) = nested {
+            state.print_expr(&self.nested_bodies[&body].value)
+        } else {
+            Ok(())
+        }
+    }
+}
 
+fn print_inlined_const(cx: &DocContext, did: DefId) -> String {
+    let body = cx.tcx.sess.cstore.maybe_get_item_body(cx.tcx, did).unwrap();
+    let inlined = InlinedConst {
+        nested_bodies: cx.tcx.sess.cstore.item_body_nested_bodies(did)
+    };
+    hir::print::to_string(&inlined, |s| s.print_expr(&body.value))
+}
+
+fn build_const(cx: &DocContext, did: DefId) -> clean::Constant {
     clean::Constant {
-        type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| cx.tcx.item_type(did).clean(cx)),
-        expr: sn
+        type_: cx.tcx.item_type(did).clean(cx),
+        expr: print_inlined_const(cx, did)
     }
 }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index fdbd2f3647c0c..3b8281980696d 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -32,7 +32,6 @@ use rustc::middle::resolve_lifetime::DefRegion::*;
 use rustc::middle::lang_items;
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
-use rustc::hir::print as pprust;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, AdtKind};
 use rustc::middle::stability;
@@ -1030,22 +1029,14 @@ pub struct Method {
     pub abi: Abi,
 }
 
-impl Clean<Method> for hir::MethodSig {
+impl<'a> Clean<Method> for (&'a hir::MethodSig, hir::BodyId) {
     fn clean(&self, cx: &DocContext) -> Method {
-        let decl = FnDecl {
-            inputs: Arguments {
-                values: self.decl.inputs.clean(cx),
-            },
-            output: self.decl.output.clean(cx),
-            variadic: false,
-            attrs: Attributes::default()
-        };
         Method {
-            generics: self.generics.clean(cx),
-            unsafety: self.unsafety,
-            constness: self.constness,
-            decl: decl,
-            abi: self.abi
+            generics: self.0.generics.clean(cx),
+            unsafety: self.0.unsafety,
+            constness: self.0.constness,
+            decl: (&*self.0.decl, self.1).clean(cx),
+            abi: self.0.abi
         }
     }
 }
@@ -1058,25 +1049,6 @@ pub struct TyMethod {
     pub abi: Abi,
 }
 
-impl Clean<TyMethod> for hir::MethodSig {
-    fn clean(&self, cx: &DocContext) -> TyMethod {
-        let decl = FnDecl {
-            inputs: Arguments {
-                values: self.decl.inputs.clean(cx),
-            },
-            output: self.decl.output.clean(cx),
-            variadic: false,
-            attrs: Attributes::default()
-        };
-        TyMethod {
-            unsafety: self.unsafety.clone(),
-            decl: decl,
-            generics: self.generics.clean(cx),
-            abi: self.abi
-        }
-    }
-}
-
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Function {
     pub decl: FnDecl,
@@ -1097,7 +1069,7 @@ impl Clean<Item> for doctree::Function {
             deprecation: self.depr.clean(cx),
             def_id: cx.tcx.map.local_def_id(self.id),
             inner: FunctionItem(Function {
-                decl: self.decl.clean(cx),
+                decl: (&self.decl, self.body).clean(cx),
                 generics: self.generics.clean(cx),
                 unsafety: self.unsafety,
                 constness: self.constness,
@@ -1130,14 +1102,47 @@ pub struct Arguments {
     pub values: Vec<Argument>,
 }
 
-impl Clean<FnDecl> for hir::FnDecl {
+impl<'a> Clean<Arguments> for (&'a [P<hir::Ty>], &'a [Spanned<ast::Name>]) {
+    fn clean(&self, cx: &DocContext) -> Arguments {
+        Arguments {
+            values: self.0.iter().enumerate().map(|(i, ty)| {
+                let mut name = self.1.get(i).map(|n| n.node.to_string())
+                                            .unwrap_or(String::new());
+                if name.is_empty() {
+                    name = "_".to_string();
+                }
+                Argument {
+                    name: name,
+                    type_: ty.clean(cx),
+                }
+            }).collect()
+        }
+    }
+}
+
+impl<'a> Clean<Arguments> for (&'a [P<hir::Ty>], hir::BodyId) {
+    fn clean(&self, cx: &DocContext) -> Arguments {
+        let body = cx.tcx.map.body(self.1);
+
+        Arguments {
+            values: self.0.iter().enumerate().map(|(i, ty)| {
+                Argument {
+                    name: name_from_pat(&body.arguments[i].pat),
+                    type_: ty.clean(cx),
+                }
+            }).collect()
+        }
+    }
+}
+
+impl<'a, A: Copy> Clean<FnDecl> for (&'a hir::FnDecl, A)
+    where (&'a [P<hir::Ty>], A): Clean<Arguments>
+{
     fn clean(&self, cx: &DocContext) -> FnDecl {
         FnDecl {
-            inputs: Arguments {
-                values: self.inputs.clean(cx),
-            },
-            output: self.output.clean(cx),
-            variadic: self.variadic,
+            inputs: (&self.0.inputs[..], self.1).clean(cx),
+            output: self.0.output.clean(cx),
+            variadic: self.0.variadic,
             attrs: Attributes::default()
         }
     }
@@ -1159,7 +1164,6 @@ impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
                 values: sig.skip_binder().inputs().iter().map(|t| {
                     Argument {
                         type_: t.clean(cx),
-                        id: ast::CRATE_NODE_ID,
                         name: names.next().map_or("".to_string(), |name| name.to_string()),
                     }
                 }).collect(),
@@ -1172,7 +1176,6 @@ impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
 pub struct Argument {
     pub type_: Type,
     pub name: String,
-    pub id: ast::NodeId,
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
@@ -1184,26 +1187,17 @@ pub enum SelfTy {
 
 impl Argument {
     pub fn to_self(&self) -> Option<SelfTy> {
-        if self.name == "self" {
-            match self.type_ {
-                Infer => Some(SelfValue),
-                BorrowedRef{ref lifetime, mutability, ref type_} if **type_ == Infer => {
-                    Some(SelfBorrowed(lifetime.clone(), mutability))
-                }
-                _ => Some(SelfExplicit(self.type_.clone()))
-            }
-        } else {
-            None
+        if self.name != "self" {
+            return None;
         }
-    }
-}
-
-impl Clean<Argument> for hir::Arg {
-    fn clean(&self, cx: &DocContext) -> Argument {
-        Argument {
-            name: name_from_pat(&*self.pat),
-            type_: (self.ty.clean(cx)),
-            id: self.id
+        if self.type_.is_self_type() {
+            return Some(SelfValue);
+        }
+        match self.type_ {
+            BorrowedRef{ref lifetime, mutability, ref type_} if type_.is_self_type() => {
+                Some(SelfBorrowed(lifetime.clone(), mutability))
+            }
+            _ => Some(SelfExplicit(self.type_.clone()))
         }
     }
 }
@@ -1269,17 +1263,22 @@ impl Clean<PolyTrait> for hir::PolyTraitRef {
 impl Clean<Item> for hir::TraitItem {
     fn clean(&self, cx: &DocContext) -> Item {
         let inner = match self.node {
-            hir::ConstTraitItem(ref ty, ref default) => {
+            hir::TraitItemKind::Const(ref ty, default) => {
                 AssociatedConstItem(ty.clean(cx),
-                                    default.as_ref().map(|e| pprust::expr_to_string(&e)))
+                                    default.map(|e| print_const_expr(cx, e)))
             }
-            hir::MethodTraitItem(ref sig, Some(_)) => {
-                MethodItem(sig.clean(cx))
+            hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
+                MethodItem((sig, body).clean(cx))
             }
-            hir::MethodTraitItem(ref sig, None) => {
-                TyMethodItem(sig.clean(cx))
+            hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => {
+                TyMethodItem(TyMethod {
+                    unsafety: sig.unsafety.clone(),
+                    decl: (&*sig.decl, &names[..]).clean(cx),
+                    generics: sig.generics.clean(cx),
+                    abi: sig.abi
+                })
             }
-            hir::TypeTraitItem(ref bounds, ref default) => {
+            hir::TraitItemKind::Type(ref bounds, ref default) => {
                 AssociatedTypeItem(bounds.clean(cx), default.clean(cx))
             }
         };
@@ -1299,12 +1298,12 @@ impl Clean<Item> for hir::TraitItem {
 impl Clean<Item> for hir::ImplItem {
     fn clean(&self, cx: &DocContext) -> Item {
         let inner = match self.node {
-            hir::ImplItemKind::Const(ref ty, ref expr) => {
+            hir::ImplItemKind::Const(ref ty, expr) => {
                 AssociatedConstItem(ty.clean(cx),
-                                    Some(pprust::expr_to_string(expr)))
+                                    Some(print_const_expr(cx, expr)))
             }
-            hir::ImplItemKind::Method(ref sig, _) => {
-                MethodItem(sig.clean(cx))
+            hir::ImplItemKind::Method(ref sig, body) => {
+                MethodItem((sig, body).clean(cx))
             }
             hir::ImplItemKind::Type(ref ty) => TypedefItem(Typedef {
                 type_: ty.clean(cx),
@@ -1353,11 +1352,13 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
                     };
                     let self_arg_ty = *fty.sig.input(0).skip_binder();
                     if self_arg_ty == self_ty {
-                        decl.inputs.values[0].type_ = Infer;
+                        decl.inputs.values[0].type_ = Generic(String::from("Self"));
                     } else if let ty::TyRef(_, mt) = self_arg_ty.sty {
                         if mt.ty == self_ty {
                             match decl.inputs.values[0].type_ {
-                                BorrowedRef{ref mut type_, ..} => **type_ = Infer,
+                                BorrowedRef{ref mut type_, ..} => {
+                                    **type_ = Generic(String::from("Self"))
+                                }
                                 _ => unreachable!(),
                             }
                         }
@@ -1568,6 +1569,13 @@ impl Type {
             _ => false,
         }
     }
+
+    pub fn is_self_type(&self) -> bool {
+        match *self {
+            Generic(ref name) => name == "Self",
+            _ => false
+        }
+    }
 }
 
 impl GetDefId for Type {
@@ -1677,11 +1685,12 @@ impl Clean<Type> for hir::Ty {
                 BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
                              type_: box m.ty.clean(cx)},
             TySlice(ref ty) => Vector(box ty.clean(cx)),
-            TyArray(ref ty, ref e) => {
+            TyArray(ref ty, e) => {
                 use rustc_const_math::{ConstInt, ConstUsize};
                 use rustc_const_eval::eval_const_expr;
                 use rustc::middle::const_val::ConstVal;
 
+                let e = &cx.tcx.map.body(e).value;
                 let n = match eval_const_expr(cx.tcx, e) {
                     ConstVal::Integral(ConstInt::Usize(u)) => match u {
                         ConstUsize::Us16(u) => u.to_string(),
@@ -2332,7 +2341,7 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy {
                 type_params: Vec::new(),
                 where_predicates: Vec::new()
             },
-            decl: self.decl.clean(cx),
+            decl: (&*self.decl, &[][..]).clean(cx),
             abi: self.abi,
         }
     }
@@ -2362,7 +2371,7 @@ impl Clean<Item> for doctree::Static {
             inner: StaticItem(Static {
                 type_: self.type_.clean(cx),
                 mutability: self.mutability.clean(cx),
-                expr: pprust::expr_to_string(&self.expr),
+                expr: print_const_expr(cx, self.expr),
             }),
         }
     }
@@ -2386,7 +2395,7 @@ impl Clean<Item> for doctree::Constant {
             deprecation: self.depr.clean(cx),
             inner: ConstantItem(Constant {
                 type_: self.type_.clean(cx),
-                expr: pprust::expr_to_string(&self.expr),
+                expr: print_const_expr(cx, self.expr),
             }),
         }
     }
@@ -2630,9 +2639,9 @@ impl Clean<Vec<Item>> for hir::ForeignMod {
 impl Clean<Item> for hir::ForeignItem {
     fn clean(&self, cx: &DocContext) -> Item {
         let inner = match self.node {
-            hir::ForeignItemFn(ref decl, ref generics) => {
+            hir::ForeignItemFn(ref decl, ref names, ref generics) => {
                 ForeignFunctionItem(Function {
-                    decl: decl.clean(cx),
+                    decl: (&**decl, &names[..]).clean(cx),
                     generics: generics.clean(cx),
                     unsafety: hir::Unsafety::Unsafe,
                     abi: Abi::Rust,
@@ -2714,6 +2723,10 @@ fn name_from_pat(p: &hir::Pat) -> String {
     }
 }
 
+fn print_const_expr(cx: &DocContext, body: hir::BodyId) -> String {
+    cx.tcx.map.node_to_pretty_string(body.node_id)
+}
+
 /// Given a type Path, resolve it to a Type using the TyCtxt
 fn resolve_type(cx: &DocContext,
                 path: Path,
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index 31e10fbd3b7d3..d819268240bad 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -156,6 +156,7 @@ pub struct Function {
     pub whence: Span,
     pub generics: hir::Generics,
     pub abi: abi::Abi,
+    pub body: hir::BodyId,
 }
 
 pub struct Typedef {
@@ -174,7 +175,7 @@ pub struct Typedef {
 pub struct Static {
     pub type_: P<hir::Ty>,
     pub mutability: hir::Mutability,
-    pub expr: P<hir::Expr>,
+    pub expr: hir::BodyId,
     pub name: Name,
     pub attrs: hir::HirVec<ast::Attribute>,
     pub vis: hir::Visibility,
@@ -186,7 +187,7 @@ pub struct Static {
 
 pub struct Constant {
     pub type_: P<hir::Ty>,
-    pub expr: P<hir::Expr>,
+    pub expr: hir::BodyId,
     pub name: Name,
     pub attrs: hir::HirVec<ast::Attribute>,
     pub vis: hir::Visibility,
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index b96a737ed0007..bb61a1dedda5d 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -495,7 +495,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> {
 
     fn visit_item(&mut self, item: &'hir hir::Item) {
         let name = if let hir::ItemImpl(.., ref ty, _) = item.node {
-            hir::print::ty_to_string(ty)
+            self.map.node_to_pretty_string(ty.id)
         } else {
             item.name.to_string()
         };
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index c93112657b96d..b0afc3d63f479 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -157,7 +157,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     unsafety: &hir::Unsafety,
                     constness: hir::Constness,
                     abi: &abi::Abi,
-                    gen: &hir::Generics) -> Function {
+                    gen: &hir::Generics,
+                    body: hir::BodyId) -> Function {
         debug!("Visiting fn");
         Function {
             id: item.id,
@@ -172,6 +173,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             unsafety: *unsafety,
             constness: constness,
             abi: *abi,
+            body: body,
         }
     }
 
@@ -410,9 +412,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 om.structs.push(self.visit_variant_data(item, name, sd, gen)),
             hir::ItemUnion(ref sd, ref gen) =>
                 om.unions.push(self.visit_union_data(item, name, sd, gen)),
-            hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, _) =>
+            hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, body) =>
                 om.fns.push(self.visit_fn(item, name, &**fd, unsafety,
-                                          constness, abi, gen)),
+                                          constness, abi, gen, body)),
             hir::ItemTy(ref ty, ref gen) => {
                 let t = Typedef {
                     ty: ty.clone(),
@@ -456,11 +458,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 };
                 om.constants.push(s);
             },
-            hir::ItemTrait(unsafety, ref gen, ref b, ref items) => {
+            hir::ItemTrait(unsafety, ref gen, ref b, ref item_ids) => {
+                let items = item_ids.iter()
+                                    .map(|ti| self.cx.tcx.map.trait_item(ti.id).clone())
+                                    .collect();
                 let t = Trait {
                     unsafety: unsafety,
                     name: name,
-                    items: items.clone(),
+                    items: items,
                     generics: gen.clone(),
                     bounds: b.iter().cloned().collect(),
                     id: item.id,
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index a5abdd922d63f..f72985fd91a3e 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1471,12 +1471,13 @@ impl Arg {
     }
 
     pub fn from_self(eself: ExplicitSelf, eself_ident: SpannedIdent) -> Arg {
+        let span = mk_sp(eself.span.lo, eself_ident.span.hi);
         let infer_ty = P(Ty {
             id: DUMMY_NODE_ID,
             node: TyKind::ImplicitSelf,
-            span: DUMMY_SP,
+            span: span,
         });
-        let arg = |mutbl, ty, span| Arg {
+        let arg = |mutbl, ty| Arg {
             pat: P(Pat {
                 id: DUMMY_NODE_ID,
                 node: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None),
@@ -1486,15 +1487,13 @@ impl Arg {
             id: DUMMY_NODE_ID,
         };
         match eself.node {
-            SelfKind::Explicit(ty, mutbl) => {
-                arg(mutbl, ty, mk_sp(eself.span.lo, eself_ident.span.hi))
-            }
-            SelfKind::Value(mutbl) => arg(mutbl, infer_ty, eself.span),
+            SelfKind::Explicit(ty, mutbl) => arg(mutbl, ty),
+            SelfKind::Value(mutbl) => arg(mutbl, infer_ty),
             SelfKind::Region(lt, mutbl) => arg(Mutability::Immutable, P(Ty {
                 id: DUMMY_NODE_ID,
                 node: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl: mutbl }),
-                span: DUMMY_SP,
-            }), eself.span),
+                span: span,
+            })),
         }
     }
 }
diff --git a/src/test/compile-fail/E0513.rs b/src/test/compile-fail/E0513.rs
deleted file mode 100644
index 726e23265241d..0000000000000
--- a/src/test/compile-fail/E0513.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::mem;
-
-fn main() {
-    unsafe {
-        let size = mem::size_of::<u32>();
-        mem::transmute_copy::<u32, [u8; size]>(&8_8); //~ ERROR E0513
-                                                      //~| NOTE no type for variable
-    }
-}
diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs
index c3fa39659b968..7c3f7a1d574f9 100644
--- a/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs
+++ b/src/test/compile-fail/associated-const-type-parameter-arrays-2.rs
@@ -25,8 +25,10 @@ impl Foo for Def {
 }
 
 pub fn test<A: Foo, B: Foo>() {
-    let _array = [4; <A as Foo>::Y]; //~ ERROR E0080
-                                     //~| non-constant path in constant
+    let _array = [4; <A as Foo>::Y];
+    //~^ ERROR cannot use an outer type parameter in this context [E0402]
+    //~| ERROR constant evaluation error [E0080]
+    //~| non-constant path in constant
 }
 
 fn main() {
diff --git a/src/test/compile-fail/associated-const-type-parameter-arrays.rs b/src/test/compile-fail/associated-const-type-parameter-arrays.rs
index ddf16a2278e5b..dcf87d5f0fc44 100644
--- a/src/test/compile-fail/associated-const-type-parameter-arrays.rs
+++ b/src/test/compile-fail/associated-const-type-parameter-arrays.rs
@@ -26,7 +26,9 @@ impl Foo for Def {
 
 pub fn test<A: Foo, B: Foo>() {
     let _array: [u32; <A as Foo>::Y];
-    //~^ ERROR the trait bound `A: Foo` is not satisfied
+    //~^ ERROR cannot use an outer type parameter in this context [E0402]
+    //~| ERROR constant evaluation error [E0080]
+    //~| non-constant path in constant
 }
 
 fn main() {
diff --git a/src/test/compile-fail/dep-graph-struct-signature.rs b/src/test/compile-fail/dep-graph-struct-signature.rs
index 235fc5051d780..36382e776ce28 100644
--- a/src/test/compile-fail/dep-graph-struct-signature.rs
+++ b/src/test/compile-fail/dep-graph-struct-signature.rs
@@ -34,9 +34,11 @@ struct WontChange {
 mod signatures {
     use WillChange;
 
-    #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
-    #[rustc_then_this_would_need(CollectItem)] //~ ERROR OK
+    #[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path
+    #[rustc_then_this_would_need(CollectItem)] //~ ERROR no path
     trait Bar {
+        #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
+        #[rustc_then_this_would_need(CollectItem)] //~ ERROR OK
         fn do_something(x: WillChange);
     }
 
diff --git a/src/test/compile-fail/dep-graph-type-alias.rs b/src/test/compile-fail/dep-graph-type-alias.rs
index 2e33f11c04b45..4cc15e8b522ac 100644
--- a/src/test/compile-fail/dep-graph-type-alias.rs
+++ b/src/test/compile-fail/dep-graph-type-alias.rs
@@ -35,8 +35,9 @@ enum Enum {
     Variant2(i32)
 }
 
-#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
+#[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path
 trait Trait {
+    #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
     fn method(&self, _: TypeAlias);
 }
 
diff --git a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs
index f8aa1ea95f0f6..eac134ff3cc7d 100644
--- a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs
+++ b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs
@@ -14,8 +14,8 @@ struct Foo<'a,'b> {
 }
 
 impl<'a,'b> Foo<'a,'b> {
-    fn bar(
-        self
+    fn bar(self:
+           Foo<'b,'a>
     //~^ ERROR mismatched method receiver
     //~| expected type `Foo<'a, 'b>`
     //~| found type `Foo<'b, 'a>`
@@ -24,7 +24,7 @@ impl<'a,'b> Foo<'a,'b> {
     //~| expected type `Foo<'a, 'b>`
     //~| found type `Foo<'b, 'a>`
     //~| lifetime mismatch
-            : Foo<'b,'a>) {}
+           ) {}
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-27008.rs b/src/test/compile-fail/issue-27008.rs
index e89bff025e006..f80135848e0c1 100644
--- a/src/test/compile-fail/issue-27008.rs
+++ b/src/test/compile-fail/issue-27008.rs
@@ -16,6 +16,4 @@ fn main() {
     //~| expected type `usize`
     //~| found type `S`
     //~| expected usize, found struct `S`
-    //~| ERROR expected `usize` for repeat count, found struct [E0306]
-    //~| expected `usize`
 }
diff --git a/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs b/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs
index b5401f7d124e2..691d8d31b412d 100644
--- a/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs
+++ b/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs
@@ -12,8 +12,8 @@
 
 fn main() {
     fn bar(n: isize) {
-        // FIXME (#24414): This error message needs improvement.
         let _x: [isize; n];
-        //~^ ERROR no type for local variable
+        //~^ ERROR attempt to use a non-constant value in a constant [E0435]
+        //~| ERROR constant evaluation error [E0080]
     }
 }
diff --git a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs
index a6f88a57b9125..f4769a7858728 100644
--- a/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs
+++ b/src/test/compile-fail/non-constant-expr-for-vec-repeat.rs
@@ -13,8 +13,9 @@
 fn main() {
     fn bar(n: usize) {
         let _x = [0; n];
-        //~^ ERROR constant evaluation error
-        //~| non-constant path in constant expression
-        //~| NOTE `n` is a variable
+        //~^ ERROR attempt to use a non-constant value in a constant [E0435]
+        //~| NOTE non-constant used with constant
+        //~| NOTE unresolved path in constant expression
+        //~| ERROR constant evaluation error [E0080]
     }
 }
diff --git a/src/test/compile-fail/repeat_count.rs b/src/test/compile-fail/repeat_count.rs
index 5d5113ce07c71..a716f3e29d488 100644
--- a/src/test/compile-fail/repeat_count.rs
+++ b/src/test/compile-fail/repeat_count.rs
@@ -13,43 +13,30 @@
 fn main() {
     let n = 1;
     let a = [0; n];
-    //~^ ERROR constant evaluation error
-    //~| non-constant path in constant expression
+    //~^ ERROR attempt to use a non-constant value in a constant [E0435]
     let b = [0; ()];
     //~^ ERROR mismatched types
     //~| expected type `usize`
     //~| found type `()`
     //~| expected usize, found ()
-    //~| ERROR expected `usize` for repeat count, found tuple [E0306]
-    //~| expected `usize`
     let c = [0; true];
     //~^ ERROR mismatched types
     //~| expected usize, found bool
-    //~| ERROR expected `usize` for repeat count, found boolean [E0306]
-    //~| expected `usize`
     let d = [0; 0.5];
     //~^ ERROR mismatched types
     //~| expected type `usize`
     //~| found type `{float}`
     //~| expected usize, found floating-point variable
-    //~| ERROR expected `usize` for repeat count, found float [E0306]
-    //~| expected `usize`
     let e = [0; "foo"];
     //~^ ERROR mismatched types
     //~| expected type `usize`
     //~| found type `&'static str`
     //~| expected usize, found reference
-    //~| ERROR expected `usize` for repeat count, found string literal [E0306]
-    //~| expected `usize`
     let f = [0; -4_isize];
-    //~^ ERROR constant evaluation error
-    //~| expected usize, found isize
-    //~| ERROR mismatched types
+    //~^ ERROR mismatched types
     //~| expected usize, found isize
     let f = [0_usize; -1_isize];
-    //~^ ERROR constant evaluation error
-    //~| expected usize, found isize
-    //~| ERROR mismatched types
+    //~^ ERROR mismatched types
     //~| expected usize, found isize
     struct G {
         g: (),
@@ -59,6 +46,4 @@ fn main() {
     //~| expected type `usize`
     //~| found type `main::G`
     //~| expected usize, found struct `main::G`
-    //~| ERROR expected `usize` for repeat count, found struct [E0306]
-    //~| expected `usize`
 }
diff --git a/src/test/incremental/hashes/consts.rs b/src/test/incremental/hashes/consts.rs
index 10c02d84b385e..28e85c94b664c 100644
--- a/src/test/incremental/hashes/consts.rs
+++ b/src/test/incremental/hashes/consts.rs
@@ -66,8 +66,10 @@ const CONST_CHANGE_TYPE_2: Option<u64> = None;
 const CONST_CHANGE_VALUE_1: i16 = 1;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 const CONST_CHANGE_VALUE_1: i16 = 2;
@@ -78,8 +80,10 @@ const CONST_CHANGE_VALUE_1: i16 = 2;
 const CONST_CHANGE_VALUE_2: i16 = 1 + 1;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 const CONST_CHANGE_VALUE_2: i16 = 1 + 2;
@@ -89,8 +93,10 @@ const CONST_CHANGE_VALUE_2: i16 = 1 + 2;
 const CONST_CHANGE_VALUE_3: i16 = 2 + 3;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 const CONST_CHANGE_VALUE_3: i16 = 2 * 3;
@@ -100,8 +106,10 @@ const CONST_CHANGE_VALUE_3: i16 = 2 * 3;
 const CONST_CHANGE_VALUE_4: i16 = 1 + 2 * 3;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 const CONST_CHANGE_VALUE_4: i16 = 1 + 2 * 4;
diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs
index aa17a24be23b6..da3a953d11eaa 100644
--- a/src/test/incremental/hashes/enum_defs.rs
+++ b/src/test/incremental/hashes/enum_defs.rs
@@ -108,8 +108,10 @@ enum EnumChangeValueCStyleVariant0 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeValueCStyleVariant0 {
@@ -126,6 +128,8 @@ enum EnumChangeValueCStyleVariant1 {
 #[cfg(not(cfail1))]
 #[rustc_dirty(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 enum EnumChangeValueCStyleVariant1 {
diff --git a/src/test/incremental/hashes/statics.rs b/src/test/incremental/hashes/statics.rs
index ac67e4349013a..7c6da3ba9fea6 100644
--- a/src/test/incremental/hashes/statics.rs
+++ b/src/test/incremental/hashes/statics.rs
@@ -119,9 +119,11 @@ static STATIC_CHANGE_TYPE_2: Option<u16> = None;
 static STATIC_CHANGE_VALUE_1: i16 = 1;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 static STATIC_CHANGE_VALUE_1: i16 = 2;
 
@@ -131,9 +133,11 @@ static STATIC_CHANGE_VALUE_1: i16 = 2;
 static STATIC_CHANGE_VALUE_2: i16 = 1 + 1;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 static STATIC_CHANGE_VALUE_2: i16 = 1 + 2;
 
@@ -142,9 +146,11 @@ static STATIC_CHANGE_VALUE_2: i16 = 1 + 2;
 static STATIC_CHANGE_VALUE_3: i16 = 2 + 3;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 static STATIC_CHANGE_VALUE_3: i16 = 2 * 3;
 
@@ -153,9 +159,11 @@ static STATIC_CHANGE_VALUE_3: i16 = 2 * 3;
 static STATIC_CHANGE_VALUE_4: i16 = 1 + 2 * 3;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 static STATIC_CHANGE_VALUE_4: i16 = 1 + 2 * 4;
 
diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs
index 391c2e75ba4d5..bc401ae93404f 100644
--- a/src/test/incremental/hashes/trait_defs.rs
+++ b/src/test/incremental/hashes/trait_defs.rs
@@ -98,11 +98,15 @@ trait TraitAddReturnType {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddReturnType {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method() -> u32;
 }
 
@@ -115,11 +119,15 @@ trait TraitChangeReturnType {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeReturnType {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method() -> u64;
 }
 
@@ -132,11 +140,15 @@ trait TraitAddParameterToMethod {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddParameterToMethod {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method(a: u32);
 }
 
@@ -146,15 +158,29 @@ trait TraitAddParameterToMethod {
 #[cfg(cfail1)]
 trait TraitChangeMethodParameterName {
     fn method(a: u32);
+    fn with_default(x: i32) {}
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeMethodParameterName {
+    // FIXME(#38501) This should preferably always be clean.
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method(b: u32);
+
+    #[rustc_clean(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_dirty(label="HirBody", cfg="cfail2")]
+    #[rustc_clean(label="HirBody", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    fn with_default(y: i32) {}
 }
 
 
@@ -166,11 +192,15 @@ trait TraitChangeMethodParameterType {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeMethodParameterType {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method(a: i64);
 }
 
@@ -183,11 +213,15 @@ trait TraitChangeMethodParameterTypeRef {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeMethodParameterTypeRef {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method(a: &mut i32);
 }
 
@@ -200,11 +234,15 @@ trait TraitChangeMethodParametersOrder {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeMethodParametersOrder {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method(b: i64, a: i32);
 }
 
@@ -253,11 +291,15 @@ trait TraitChangeModeSelfRefToMut {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeModeSelfRefToMut {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method(&mut self);
 }
 
@@ -269,11 +311,15 @@ trait TraitChangeModeSelfOwnToMut: Sized {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeModeSelfOwnToMut: Sized {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method(mut self) {}
 }
 
@@ -285,11 +331,15 @@ trait TraitChangeModeSelfOwnToRef {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeModeSelfOwnToRef {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method(&self);
 }
 
@@ -302,11 +352,15 @@ trait TraitAddUnsafeModifier {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddUnsafeModifier {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     unsafe fn method();
 }
 
@@ -319,11 +373,15 @@ trait TraitAddExternModifier {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddExternModifier {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     extern fn method();
 }
 
@@ -336,11 +394,15 @@ trait TraitChangeExternCToRustIntrinsic {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeExternCToRustIntrinsic {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     extern "rust-intrinsic" fn method();
 }
 
@@ -353,11 +415,15 @@ trait TraitAddTypeParameterToMethod {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddTypeParameterToMethod {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method<T>();
 }
 
@@ -370,11 +436,15 @@ trait TraitAddLifetimeParameterToMethod {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddLifetimeParameterToMethod {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method<'a>();
 }
 
@@ -391,11 +461,15 @@ trait TraitAddTraitBoundToMethodTypeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddTraitBoundToMethodTypeParameter {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method<T: ReferencedTrait0>();
 }
 
@@ -408,11 +482,15 @@ trait TraitAddBuiltinBoundToMethodTypeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddBuiltinBoundToMethodTypeParameter {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method<T: Sized>();
 }
 
@@ -425,11 +503,15 @@ trait TraitAddLifetimeBoundToMethodLifetimeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddLifetimeBoundToMethodLifetimeParameter {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method<'a, 'b: 'a>(a: &'a u32, b: &'b u32);
 }
 
@@ -442,11 +524,15 @@ trait TraitAddSecondTraitBoundToMethodTypeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddSecondTraitBoundToMethodTypeParameter {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method<T: ReferencedTrait0 + ReferencedTrait1>();
 }
 
@@ -459,11 +545,15 @@ trait TraitAddSecondBuiltinBoundToMethodTypeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddSecondBuiltinBoundToMethodTypeParameter {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method<T: Sized + Sync>();
 }
 
@@ -476,11 +566,15 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     fn method<'a, 'b, 'c: 'a + 'b>(a: &'a u32, b: &'b u32, c: &'c u32);
 }
 
@@ -514,11 +608,15 @@ trait TraitAddTraitBoundToAssociatedType {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddTraitBoundToAssociatedType {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     type Associated: ReferencedTrait0;
 
     fn mathod();
@@ -535,11 +633,15 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitAddLifetimeBoundToAssociatedType<'a> {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     type Associated: 'a;
 
     fn mathod();
@@ -617,11 +719,15 @@ trait TraitChangeTypeOfAssociatedConstant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_dirty(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 trait TraitChangeTypeOfAssociatedConstant {
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
     const Value: f64;
 
     fn mathod();
@@ -1013,11 +1119,15 @@ mod change_return_type_of_method_indirectly_use {
     #[cfg(not(cfail1))]
     use super::ReferenceType1 as ReturnType;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     trait TraitChangeReturnType {
+        #[rustc_dirty(label="Hir", cfg="cfail2")]
+        #[rustc_clean(label="Hir", cfg="cfail3")]
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
         fn method() -> ReturnType;
     }
 }
@@ -1031,11 +1141,15 @@ mod change_method_parameter_type_indirectly_by_use {
     #[cfg(not(cfail1))]
     use super::ReferenceType1 as ArgType;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     trait TraitChangeArgType {
+        #[rustc_dirty(label="Hir", cfg="cfail2")]
+        #[rustc_clean(label="Hir", cfg="cfail3")]
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
         fn method(a: ArgType);
     }
 }
@@ -1049,11 +1163,15 @@ mod change_method_parameter_type_bound_indirectly_by_use {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait1 as Bound;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     trait TraitChangeBoundOfMethodTypeParameter {
+        #[rustc_dirty(label="Hir", cfg="cfail2")]
+        #[rustc_clean(label="Hir", cfg="cfail3")]
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
         fn method<T: Bound>(a: T);
     }
 }
@@ -1068,11 +1186,15 @@ mod change_method_parameter_type_bound_indirectly_by_use_where {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait1 as Bound;
 
-    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
     #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     trait TraitChangeBoundOfMethodTypeParameterWhere {
+        #[rustc_dirty(label="Hir", cfg="cfail2")]
+        #[rustc_clean(label="Hir", cfg="cfail3")]
+        #[rustc_metadata_dirty(cfg="cfail2")]
+        #[rustc_metadata_clean(cfg="cfail3")]
         fn method<T>(a: T) where T: Bound;
     }
 }
diff --git a/src/test/incremental/string_constant.rs b/src/test/incremental/string_constant.rs
index ba8d3cc934bfc..8651a67bae221 100644
--- a/src/test/incremental/string_constant.rs
+++ b/src/test/incremental/string_constant.rs
@@ -23,14 +23,14 @@ fn main() { }
 mod x {
     #[cfg(rpass1)]
     pub fn x() {
-        println!("1");
+        println!("{}", "1");
     }
 
     #[cfg(rpass2)]
     #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
     #[rustc_dirty(label="TransCrateItem", cfg="rpass2")]
     pub fn x() {
-        println!("2");
+        println!("{}", "2");
     }
 }
 
diff --git a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot
index c1d6e3023fbc1..b0491fe6e27fd 100644
--- a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot
@@ -1,15 +1,15 @@
 digraph block {
     N0[label="entry"];
     N1[label="exit"];
-    N2[label="stmt "];
+    N2[label="stmt fn inner(x: isize) -> isize { x + x }"];
     N3[label="expr inner"];
     N4[label="expr inner"];
     N5[label="expr 18"];
     N6[label="expr inner(18)"];
     N7[label="expr inner(inner(18))"];
     N8[label="stmt inner(inner(18));"];
-    N9[label="block { inner(inner(18)); }"];
-    N10[label="expr { inner(inner(18)); }"];
+    N9[label="block {\l    fn inner(x: isize) -> isize { x + x }\l    inner(inner(18));\l}\l"];
+    N10[label="expr {\l    fn inner(x: isize) -> isize { x + x }\l    inner(inner(18));\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
diff --git a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot
index d2f9f41f647be..223978c3d7634 100644
--- a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot
+++ b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot
@@ -1,8 +1,8 @@
 digraph block {
     N0[label="entry"];
     N1[label="exit"];
-    N2[label="stmt "];
-    N3[label="stmt "];
+    N2[label="stmt struct S19 {\l    x: isize,\l}\l"];
+    N3[label="stmt impl S19 {\l    fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l}\l"];
     N4[label="expr 19"];
     N5[label="expr S19{x: 19,}"];
     N6[label="local s"];
@@ -11,8 +11,8 @@ digraph block {
     N9[label="expr s.inner()"];
     N10[label="expr s.inner().inner()"];
     N11[label="stmt s.inner().inner();"];
-    N12[label="block { let s = S19{x: 19,}; s.inner().inner(); }"];
-    N13[label="expr { let s = S19{x: 19,}; s.inner().inner(); }"];
+    N12[label="block {\l    struct S19 {\l        x: isize,\l    }\l    impl S19 {\l        fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l    }\l    let s = S19{x: 19,};\l    s.inner().inner();\l}\l"];
+    N13[label="expr {\l    struct S19 {\l        x: isize,\l    }\l    impl S19 {\l        fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l    }\l    let s = S19{x: 19,};\l    s.inner().inner();\l}\l"];
     N0 -> N2;
     N2 -> N3;
     N3 -> N4;
diff --git a/src/test/run-make/pretty-print-path-suffix/foo_method.pp b/src/test/run-make/pretty-print-path-suffix/foo_method.pp
index 696e0544fdc57..fae134986872e 100644
--- a/src/test/run-make/pretty-print-path-suffix/foo_method.pp
+++ b/src/test/run-make/pretty-print-path-suffix/foo_method.pp
@@ -12,5 +12,6 @@
 
 
 
-fn foo_method(&self) -> &'static str { return "i am very similar to foo."; }
-/* nest::{{impl}}::foo_method */
+fn foo_method(self: &Self)
+ -> &'static str { return "i am very similar to foo."; } /*
+nest::{{impl}}::foo_method */
diff --git a/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs b/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs
index c6892757c682f..e1b1b441894b7 100644
--- a/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs
+++ b/src/test/run-pass-fulldeps/issue-37290/auxiliary/lint.rs
@@ -41,12 +41,12 @@ impl LintPass for Pass {
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
     fn check_fn(&mut self, cx: &LateContext,
-                              fk: FnKind, _: &hir::FnDecl, expr: &hir::Expr,
+                              fk: FnKind, _: &hir::FnDecl, body: &hir::Body,
                               span: Span, node: ast::NodeId)
     {
         if let FnKind::Closure(..) = fk { return }
 
-        let mut extent = cx.tcx.region_maps.node_extent(expr.id);
+        let mut extent = cx.tcx.region_maps.node_extent(body.value.id);
         while let Some(parent) = cx.tcx.region_maps.opt_encl_scope(extent) {
             extent = parent;
         }
diff --git a/src/test/ui/span/mut-arg-hint.stderr b/src/test/ui/span/mut-arg-hint.stderr
index 5e9a0b915031e..58f66c1358437 100644
--- a/src/test/ui/span/mut-arg-hint.stderr
+++ b/src/test/ui/span/mut-arg-hint.stderr
@@ -1,11 +1,3 @@
-error: cannot borrow immutable borrowed content `*a` as mutable
-  --> $DIR/mut-arg-hint.rs:13:9
-   |
-12 |     fn foo(mut a: &String) {
-   |                   ------- use `&mut String` here to make mutable
-13 |         a.push_str("bar");
-   |         ^
-
 error: cannot borrow immutable borrowed content `*a` as mutable
   --> $DIR/mut-arg-hint.rs:18:5
    |
@@ -14,6 +6,14 @@ error: cannot borrow immutable borrowed content `*a` as mutable
 18 |     a.push_str("foo");
    |     ^
 
+error: cannot borrow immutable borrowed content `*a` as mutable
+  --> $DIR/mut-arg-hint.rs:13:9
+   |
+12 |     fn foo(mut a: &String) {
+   |                   ------- use `&mut String` here to make mutable
+13 |         a.push_str("bar");
+   |         ^
+
 error: cannot borrow immutable borrowed content `*a` as mutable
   --> $DIR/mut-arg-hint.rs:25:9
    |