about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/dep_graph/dep_node.rs8
-rw-r--r--src/librustc/hir/intravisit.rs158
-rw-r--r--src/librustc/hir/itemlikevisit.rs6
-rw-r--r--src/librustc/hir/lowering.rs53
-rw-r--r--src/librustc/hir/map/blocks.rs42
-rw-r--r--src/librustc/hir/map/collector.rs10
-rw-r--r--src/librustc/hir/map/def_collector.rs15
-rw-r--r--src/librustc/hir/map/mod.rs75
-rw-r--r--src/librustc/hir/mod.rs29
-rw-r--r--src/librustc/hir/print.rs17
-rw-r--r--src/librustc/lint/context.rs25
-rw-r--r--src/librustc/middle/cstore.rs110
-rw-r--r--src/librustc/middle/dataflow.rs4
-rw-r--r--src/librustc/middle/dead.rs33
-rw-r--r--src/librustc/middle/effect.rs20
-rw-r--r--src/librustc/middle/entry.rs1
-rw-r--r--src/librustc/middle/intrinsicck.rs28
-rw-r--r--src/librustc/middle/liveness.rs68
-rw-r--r--src/librustc/middle/mem_categorization.rs2
-rw-r--r--src/librustc/middle/reachable.rs26
-rw-r--r--src/librustc/middle/region.rs80
-rw-r--r--src/librustc/middle/resolve_lifetime.rs30
-rw-r--r--src/librustc/middle/stability.rs39
-rw-r--r--src/librustc/middle/weak_lang_items.rs6
-rw-r--r--src/librustc/ty/mod.rs14
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs16
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs56
-rw-r--r--src/librustc_const_eval/check_match.rs36
-rw-r--r--src/librustc_const_eval/eval.rs126
-rw-r--r--src/librustc_driver/pretty.rs7
-rw-r--r--src/librustc_incremental/calculate_svh/mod.rs28
-rw-r--r--src/librustc_incremental/calculate_svh/svh_visitor.rs25
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs6
-rw-r--r--src/librustc_incremental/persist/hash.rs6
-rw-r--r--src/librustc_incremental/persist/save.rs4
-rw-r--r--src/librustc_metadata/astencode.rs32
-rw-r--r--src/librustc_metadata/cstore_impl.rs26
-rw-r--r--src/librustc_metadata/encoder.rs25
-rw-r--r--src/librustc_mir/hair/cx/expr.rs2
-rw-r--r--src/librustc_mir/hair/cx/mod.rs7
-rw-r--r--src/librustc_mir/mir_map.rs14
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs14
-rw-r--r--src/librustc_passes/consts.rs83
-rw-r--r--src/librustc_passes/hir_stats.rs4
-rw-r--r--src/librustc_passes/loops.rs18
-rw-r--r--src/librustc_passes/rvalues.rs17
-rw-r--r--src/librustc_passes/static_recursion.rs10
-rw-r--r--src/librustc_privacy/lib.rs34
-rw-r--r--src/librustc_trans/symbol_names_test.rs6
-rw-r--r--src/librustc_typeck/check/closure.rs3
-rw-r--r--src/librustc_typeck/check/mod.rs44
-rw-r--r--src/librustc_typeck/check/regionck.rs52
-rw-r--r--src/librustc_typeck/check/upvar.rs35
-rw-r--r--src/librustc_typeck/check/wfcheck.rs14
-rw-r--r--src/librustc_typeck/check/writeback.rs26
-rw-r--r--src/librustc_typeck/coherence/orphan.rs1
-rw-r--r--src/librustc_typeck/collect.rs71
-rw-r--r--src/librustdoc/test.rs4
-rw-r--r--src/test/incremental/change_private_impl_method_cc/struct_point.rs11
-rw-r--r--src/test/incremental/change_pub_inherent_method_body/struct_point.rs7
-rw-r--r--src/test/incremental/hashes/call_expressions.rs54
-rw-r--r--src/test/incremental/hashes/for_loops.rs66
-rw-r--r--src/test/incremental/hashes/if_expressions.rs48
-rw-r--r--src/test/incremental/hashes/let_expressions.rs72
-rw-r--r--src/test/incremental/hashes/loop_expressions.rs48
-rw-r--r--src/test/incremental/hashes/match_expressions.rs78
-rw-r--r--src/test/incremental/hashes/panic_exprs.rs46
-rw-r--r--src/test/incremental/hashes/panic_exprs_no_overflow_checks.rs54
-rw-r--r--src/test/incremental/hashes/struct_constructors.rs42
-rw-r--r--src/test/incremental/hashes/unary_and_binary_exprs.rs224
-rw-r--r--src/test/incremental/hashes/while_let_loops.rs54
-rw-r--r--src/test/incremental/hashes/while_loops.rs54
-rw-r--r--src/test/incremental/hello_world.rs12
-rw-r--r--src/test/incremental/ich_method_call_trait_scope.rs4
-rw-r--r--src/test/incremental/ich_nested_items.rs3
-rw-r--r--src/test/incremental/ich_resolve_results.rs8
-rw-r--r--src/test/incremental/source_loc_macros.rs9
-rw-r--r--src/test/incremental/spans_insignificant_w_o_debuginfo.rs1
-rw-r--r--src/test/incremental/spans_significant_w_debuginfo.rs1
-rw-r--r--src/test/run-pass/associated-const-const-eval.rs30
-rw-r--r--src/test/run-pass/associated-const-cross-crate-const-eval.rs38
81 files changed, 1807 insertions, 908 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 397d61d5372..0c941a4a230 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -42,6 +42,10 @@ pub enum DepNode<D: Clone + Debug> {
     // Represents the HIR node with the given node-id
     Hir(D),
 
+    // Represents the body of a function or method. The def-id is that of the
+    // function/method.
+    HirBody(D),
+
     // Represents the metadata for a given HIR node, typically found
     // in an extern crate.
     MetaData(D),
@@ -59,6 +63,7 @@ pub enum DepNode<D: Clone + Debug> {
     PluginRegistrar,
     StabilityIndex,
     CollectItem(D),
+    CollectItemSig(D),
     Coherence,
     EffectCheck,
     Liveness,
@@ -150,6 +155,7 @@ impl<D: Clone + Debug> DepNode<D> {
             CollectItem,
             BorrowCheck,
             Hir,
+            HirBody,
             TransCrateItem,
             TypeckItemType,
             TypeckItemBody,
@@ -199,8 +205,10 @@ impl<D: Clone + Debug> DepNode<D> {
             WorkProduct(ref id) => Some(WorkProduct(id.clone())),
 
             Hir(ref d) => op(d).map(Hir),
+            HirBody(ref d) => op(d).map(HirBody),
             MetaData(ref d) => op(d).map(MetaData),
             CollectItem(ref d) => op(d).map(CollectItem),
+            CollectItemSig(ref d) => op(d).map(CollectItemSig),
             CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
             CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
             CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 94da10d33f8..625bde2ca8b 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -67,6 +67,62 @@ impl<'a> FnKind<'a> {
     }
 }
 
+/// Specifies what nested things a visitor wants to visit. The most
+/// common choice is `OnlyBodies`, which will cause the visitor to
+/// visit fn bodies for fns that it encounters, but skip over nested
+/// item-like things.
+///
+/// See the comments on `ItemLikeVisitor` for more details on the overall
+/// visit strategy.
+pub enum NestedVisitorMap<'this, 'tcx: 'this> {
+    /// Do not visit any nested things. When you add a new
+    /// "non-nested" thing, you will want to audit such uses to see if
+    /// they remain valid.
+    ///
+    /// Use this if you are only walking some particular kind of tree
+    /// (i.e., a type, or fn signature) and you don't want to thread a
+    /// HIR map around.
+    None,
+
+    /// Do not visit nested item-like things, but visit nested things
+    /// that are inside of an item-like.
+    ///
+    /// **This is the most common choice.** A very commmon pattern is
+    /// to use `tcx.visit_all_item_likes_in_krate()` as an outer loop,
+    /// and to have the visitor that visits the contents of each item
+    /// using this setting.
+    OnlyBodies(&'this Map<'tcx>),
+
+    /// Visit all nested things, including item-likes.
+    ///
+    /// **This is an unusual choice.** It is used when you want to
+    /// process everything within their lexical context. Typically you
+    /// kick off the visit by doing `walk_krate()`.
+    All(&'this Map<'tcx>),
+}
+
+impl<'this, 'tcx> NestedVisitorMap<'this, 'tcx> {
+    /// Returns the map to use for an "intra item-like" thing (if any).
+    /// e.g., function body.
+    pub fn intra(self) -> Option<&'this Map<'tcx>> {
+        match self {
+            NestedVisitorMap::None => None,
+            NestedVisitorMap::OnlyBodies(map) => Some(map),
+            NestedVisitorMap::All(map) => Some(map),
+        }
+    }
+
+    /// Returns the map to use for an "item-like" thing (if any).
+    /// e.g., item, impl-item.
+    pub fn inter(self) -> Option<&'this Map<'tcx>> {
+        match self {
+            NestedVisitorMap::None => None,
+            NestedVisitorMap::OnlyBodies(_) => None,
+            NestedVisitorMap::All(map) => Some(map),
+        }
+    }
+}
+
 /// Each method of the Visitor trait is a hook to be potentially
 /// overridden.  Each method's default implementation recursively visits
 /// the substructure of the input via the corresponding `walk` method;
@@ -88,13 +144,14 @@ pub trait Visitor<'v> : Sized {
     // Nested items.
 
     /// The default versions of the `visit_nested_XXX` routines invoke
-    /// this method to get a map to use; if they get back `None`, they
-    /// just skip nested things. Otherwise, they will lookup the
-    /// nested item-like things in the map and visit it. So the best
-    /// way to implement a nested visitor is to override this method
-    /// to return a `Map`; one advantage of this is that if we add
-    /// more types of nested things in the future, they will
-    /// automatically work.
+    /// this method to get a map to use. By selecting an enum variant,
+    /// you control which kinds of nested HIR are visited; see
+    /// `NestedVisitorMap` for details. By "nested HIR", we are
+    /// referring to bits of HIR that are not directly embedded within
+    /// one another but rather indirectly, through a table in the
+    /// crate. This is done to control dependencies during incremental
+    /// compilation: the non-inline bits of HIR can be tracked and
+    /// hashed separately.
     ///
     /// **If for some reason you want the nested behavior, but don't
     /// have a `Map` are your disposal:** then you should override the
@@ -102,9 +159,7 @@ pub trait Visitor<'v> : Sized {
     /// `panic!()`. This way, if a new `visit_nested_XXX` variant is
     /// added in the future, we will see the panic in your code and
     /// fix it appropriately.
-    fn nested_visit_map(&mut self) -> Option<&Map<'v>> {
-        None
-    }
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v>;
 
     /// Invoked when a nested item is encountered. By default does
     /// nothing unless you override `nested_visit_map` to return
@@ -116,8 +171,7 @@ pub trait Visitor<'v> : Sized {
     /// but cannot supply a `Map`; see `nested_visit_map` for advice.
     #[allow(unused_variables)]
     fn visit_nested_item(&mut self, id: ItemId) {
-        let opt_item = self.nested_visit_map()
-                           .map(|map| map.expect_item(id.id));
+        let opt_item = self.nested_visit_map().inter().map(|map| map.expect_item(id.id));
         if let Some(item) = opt_item {
             self.visit_item(item);
         }
@@ -128,13 +182,23 @@ pub trait Visitor<'v> : Sized {
     /// method.
     #[allow(unused_variables)]
     fn visit_nested_impl_item(&mut self, id: ImplItemId) {
-        let opt_item = self.nested_visit_map()
-                           .map(|map| map.impl_item(id));
+        let opt_item = self.nested_visit_map().inter().map(|map| map.impl_item(id));
         if let Some(item) = opt_item {
             self.visit_impl_item(item);
         }
     }
 
+    /// Invoked to visit the body of a function, method or closure. Like
+    /// 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);
+        }
+    }
+
     /// Visit the top-level item and (optionally) nested items / impl items. See
     /// `visit_nested_item` for details.
     fn visit_item(&mut self, i: &'v Item) {
@@ -200,7 +264,7 @@ pub trait Visitor<'v> : Sized {
     fn visit_where_predicate(&mut self, predicate: &'v WherePredicate) {
         walk_where_predicate(self, predicate)
     }
-    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Expr, s: Span, id: NodeId) {
+    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: ExprId, s: Span, id: NodeId) {
         walk_fn(self, fk, fd, b, s, id)
     }
     fn visit_trait_item(&mut self, ti: &'v TraitItem) {
@@ -363,7 +427,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
             visitor.visit_ty(typ);
             visitor.visit_expr(expr);
         }
-        ItemFn(ref declaration, unsafety, constness, abi, ref generics, ref body) => {
+        ItemFn(ref declaration, unsafety, constness, abi, ref generics, body_id) => {
             visitor.visit_fn(FnKind::ItemFn(item.name,
                                             generics,
                                             unsafety,
@@ -372,7 +436,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
                                             &item.vis,
                                             &item.attrs),
                              declaration,
-                             body,
+                             body_id,
                              item.span,
                              item.id)
         }
@@ -697,13 +761,25 @@ 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,
-                                   function_body: &'v Expr,
+                                   body_id: ExprId,
                                    _span: Span,
                                    id: NodeId) {
     visitor.visit_id(id);
     walk_fn_decl(visitor, function_declaration);
     walk_fn_kind(visitor, function_kind);
-    visitor.visit_expr(function_body)
+    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);
+    walk_fn_decl(visitor, function_declaration);
+    walk_fn_kind(visitor, function_kind);
+    visitor.visit_expr(body)
 }
 
 pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) {
@@ -720,13 +796,13 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
             visitor.visit_generics(&sig.generics);
             walk_fn_decl(visitor, &sig.decl);
         }
-        MethodTraitItem(ref sig, Some(ref body)) => {
+        MethodTraitItem(ref sig, Some(body_id)) => {
             visitor.visit_fn(FnKind::Method(trait_item.name,
                                             sig,
                                             None,
                                             &trait_item.attrs),
                              &sig.decl,
-                             body,
+                             body_id,
                              trait_item.span,
                              trait_item.id);
         }
@@ -752,13 +828,13 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
             visitor.visit_ty(ty);
             visitor.visit_expr(expr);
         }
-        ImplItemKind::Method(ref sig, ref body) => {
+        ImplItemKind::Method(ref sig, body_id) => {
             visitor.visit_fn(FnKind::Method(impl_item.name,
                                             sig,
                                             Some(&impl_item.vis),
                                             &impl_item.attrs),
                              &sig.decl,
-                             body,
+                             body_id,
                              impl_item.span,
                              impl_item.id);
         }
@@ -883,7 +959,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             visitor.visit_expr(subexpression);
             walk_list!(visitor, visit_arm, arms);
         }
-        ExprClosure(_, ref function_declaration, ref body, _fn_decl_span) => {
+        ExprClosure(_, ref function_declaration, body, _fn_decl_span) => {
             visitor.visit_fn(FnKind::Closure(&expression.attrs),
                              function_declaration,
                              body,
@@ -998,13 +1074,14 @@ impl IdRange {
 }
 
 
-pub struct IdRangeComputingVisitor {
-    pub result: IdRange,
+pub struct IdRangeComputingVisitor<'a, 'ast: 'a> {
+    result: IdRange,
+    map: &'a map::Map<'ast>,
 }
 
-impl IdRangeComputingVisitor {
-    pub fn new() -> IdRangeComputingVisitor {
-        IdRangeComputingVisitor { result: IdRange::max() }
+impl<'a, 'ast> IdRangeComputingVisitor<'a, 'ast> {
+    pub fn new(map: &'a map::Map<'ast>) -> IdRangeComputingVisitor<'a, 'ast> {
+        IdRangeComputingVisitor { result: IdRange::max(), map: map }
     }
 
     pub fn result(&self) -> IdRange {
@@ -1012,20 +1089,25 @@ impl IdRangeComputingVisitor {
     }
 }
 
-impl<'v> Visitor<'v> for IdRangeComputingVisitor {
+impl<'a, 'ast> Visitor<'ast> for IdRangeComputingVisitor<'a, 'ast> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'ast> {
+        NestedVisitorMap::OnlyBodies(&self.map)
+    }
+
     fn visit_id(&mut self, id: NodeId) {
         self.result.add(id);
     }
 }
 
 /// Computes the id range for a single fn body, ignoring nested items.
-pub fn compute_id_range_for_fn_body(fk: FnKind,
-                                    decl: &FnDecl,
-                                    body: &Expr,
-                                    sp: Span,
-                                    id: NodeId)
-                                    -> IdRange {
-    let mut visitor = IdRangeComputingVisitor::new();
-    visitor.visit_fn(fk, decl, body, sp, id);
+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 1e373441e9e..71ef7131440 100644
--- a/src/librustc/hir/itemlikevisit.rs
+++ b/src/librustc/hir/itemlikevisit.rs
@@ -41,8 +41,10 @@ use super::intravisit::Visitor;
 ///    item-like things.
 ///    - Example: Lifetime resolution, which wants to bring lifetimes declared on the
 ///      impl into scope while visiting the impl-items, and then back out again.
-///    - How: Implement `intravisit::Visitor` and override the `visit_nested_foo()` foo methods
-///      as needed. Walk your crate with `intravisit::walk_crate()` invoked on `tcx.map.krate()`.
+///    - How: Implement `intravisit::Visitor` and override the
+///      `visit_nested_map()` methods to return
+///      `NestedVisitorMap::All`. Walk your crate with
+///      `intravisit::walk_crate()` invoked on `tcx.map.krate()`.
 ///    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
 ///    - Pro: Preserves nesting information
 ///    - Con: Does not integrate well into dependency tracking.
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index f9f46558dec..ccf94e0b803 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -47,9 +47,12 @@ 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 std::collections::BTreeMap;
 use std::iter;
+use std::mem;
+
 use syntax::ast::*;
 use syntax::errors;
 use syntax::ptr::P;
@@ -68,6 +71,7 @@ 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.
@@ -104,6 +108,7 @@ 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(),
         impl_items: BTreeMap::new(),
@@ -120,6 +125,23 @@ enum ParamMode {
 
 impl<'a> LoweringContext<'a> {
     fn lower_crate(mut self, c: &Crate) -> hir::Crate {
+        self.lower_items(c);
+        let module = self.lower_mod(&c.module);
+        let attrs = self.lower_attrs(&c.attrs);
+        let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect();
+
+        hir::Crate {
+            module: module,
+            attrs: attrs,
+            span: c.span,
+            exported_macros: exported_macros,
+            items: self.items,
+            impl_items: self.impl_items,
+            exprs: mem::replace(&mut self.exprs, FnvHashMap()),
+        }
+    }
+
+    fn lower_items(&mut self, c: &Crate) {
         struct ItemLowerer<'lcx, 'interner: 'lcx> {
             lctx: &'lcx mut LoweringContext<'interner>,
         }
@@ -139,16 +161,14 @@ impl<'a> LoweringContext<'a> {
             }
         }
 
-        visit::walk_crate(&mut ItemLowerer { lctx: &mut self }, c);
+        let mut item_lowerer = ItemLowerer { lctx: self };
+        visit::walk_crate(&mut item_lowerer, c);
+    }
 
-        hir::Crate {
-            module: self.lower_mod(&c.module),
-            attrs: self.lower_attrs(&c.attrs),
-            span: c.span,
-            exported_macros: c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(),
-            items: self.items,
-            impl_items: self.impl_items,
-        }
+    fn record_expr(&mut self, expr: hir::Expr) -> hir::ExprId {
+        let id = hir::ExprId(expr.id);
+        self.exprs.insert(id, expr);
+        id
     }
 
     fn next_id(&self) -> NodeId {
@@ -825,12 +845,14 @@ impl<'a> LoweringContext<'a> {
             }
             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);
                 hir::ItemFn(self.lower_fn_decl(decl),
                             self.lower_unsafety(unsafety),
                             self.lower_constness(constness),
                             abi,
                             self.lower_generics(generics),
-                            P(self.expr_block(body, ThinVec::new())))
+                            body_id)
             }
             ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)),
             ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)),
@@ -897,7 +919,8 @@ impl<'a> LoweringContext<'a> {
                         hir::MethodTraitItem(this.lower_method_sig(sig),
                                              body.as_ref().map(|x| {
                             let body = this.lower_block(x);
-                            P(this.expr_block(body, ThinVec::new()))
+                            let expr = this.expr_block(body, ThinVec::new());
+                            this.record_expr(expr)
                         }))
                     }
                     TraitItemKind::Type(ref bounds, ref default) => {
@@ -925,8 +948,9 @@ impl<'a> LoweringContext<'a> {
                     }
                     ImplItemKind::Method(ref sig, ref body) => {
                         let body = this.lower_block(body);
-                        hir::ImplItemKind::Method(this.lower_method_sig(sig),
-                                                  P(this.expr_block(body, ThinVec::new())))
+                        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)
                     }
                     ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)),
                     ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
@@ -1375,9 +1399,10 @@ impl<'a> LoweringContext<'a> {
                 }
                 ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => {
                     self.with_parent_def(e.id, |this| {
+                        let expr = this.lower_expr(body);
                         hir::ExprClosure(this.lower_capture_clause(capture_clause),
                                          this.lower_fn_decl(decl),
-                                         P(this.lower_expr(body)),
+                                         this.record_expr(expr),
                                          fn_decl_span)
                     })
                 }
diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs
index 325a90ea91e..068e7ed8624 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: &'a Expr,
+    pub body: ast::ExprId,
     pub kind: FnKind<'a>,
     pub span: Span,
     pub id:   NodeId,
@@ -115,7 +115,7 @@ struct ItemFnParts<'a> {
     abi:      abi::Abi,
     vis:      &'a ast::Visibility,
     generics: &'a ast::Generics,
-    body:     &'a Expr,
+    body:     ast::ExprId,
     id:       NodeId,
     span:     Span,
     attrs:    &'a [Attribute],
@@ -125,14 +125,14 @@ struct ItemFnParts<'a> {
 /// for use when implementing FnLikeNode operations.
 struct ClosureParts<'a> {
     decl: &'a FnDecl,
-    body: &'a Expr,
+    body: ast::ExprId,
     id: NodeId,
     span: Span,
     attrs: &'a [Attribute],
 }
 
 impl<'a> ClosureParts<'a> {
-    fn new(d: &'a FnDecl, b: &'a Expr, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
+    fn new(d: &'a FnDecl, b: ast::ExprId, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
         ClosureParts {
             decl: d,
             body: b,
@@ -172,9 +172,9 @@ impl<'a> FnLikeNode<'a> {
         }
     }
 
-    pub fn body(self) -> &'a Expr {
-        self.handle(|i: ItemFnParts<'a>|  &*i.body,
-                    |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Expr, _, _|  body,
+    pub fn body(self) -> ast::ExprId {
+        self.handle(|i: ItemFnParts<'a>|  i.body,
+                    |_, _, _: &'a ast::MethodSig, _, body: ast::ExprId, _, _|  body,
                     |c: ClosureParts<'a>| c.body)
     }
 
@@ -196,6 +196,18 @@ impl<'a> FnLikeNode<'a> {
                     |c: ClosureParts|    c.id)
     }
 
+    pub fn constness(self) -> ast::Constness {
+        match self.kind() {
+            FnKind::ItemFn(_, _, _, constness, ..) => {
+                constness
+            }
+            FnKind::Method(_, m, ..) => {
+                m.constness
+            }
+            _ => ast::Constness::NotConst
+        }
+    }
+
     pub fn kind(self) -> FnKind<'a> {
         let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
             FnKind::ItemFn(p.name, p.generics, p.unsafety, p.constness, p.abi, p.vis, p.attrs)
@@ -215,7 +227,7 @@ impl<'a> FnLikeNode<'a> {
                   Name,
                   &'a ast::MethodSig,
                   Option<&'a ast::Visibility>,
-                  &'a ast::Expr,
+                  ast::ExprId,
                   Span,
                   &'a [Attribute])
                   -> A,
@@ -223,13 +235,13 @@ impl<'a> FnLikeNode<'a> {
     {
         match self.node {
             map::NodeItem(i) => match i.node {
-                ast::ItemFn(ref decl, unsafety, constness, abi, ref generics, ref block) =>
+                ast::ItemFn(ref decl, unsafety, constness, abi, ref generics, block) =>
                     item_fn(ItemFnParts {
                         id: i.id,
                         name: i.name,
                         decl: &decl,
                         unsafety: unsafety,
-                        body: &block,
+                        body: block,
                         generics: generics,
                         abi: abi,
                         vis: &i.vis,
@@ -240,24 +252,24 @@ impl<'a> FnLikeNode<'a> {
                 _ => bug!("item FnLikeNode that is not fn-like"),
             },
             map::NodeTraitItem(ti) => match ti.node {
-                ast::MethodTraitItem(ref sig, Some(ref body)) => {
+                ast::MethodTraitItem(ref sig, Some(body)) => {
                     method(ti.id, ti.name, sig, None, body, ti.span, &ti.attrs)
                 }
                 _ => bug!("trait method FnLikeNode that is not fn-like"),
             },
             map::NodeImplItem(ii) => {
                 match ii.node {
-                    ast::ImplItemKind::Method(ref sig, ref body) => {
+                    ast::ImplItemKind::Method(ref sig, body) => {
                         method(ii.id, ii.name, sig, Some(&ii.vis), body, ii.span, &ii.attrs)
                     }
                     _ => {
                         bug!("impl method FnLikeNode that is not fn-like")
                     }
                 }
-            }
+            },
             map::NodeExpr(e) => match e.node {
-                ast::ExprClosure(_, ref decl, ref block, _fn_decl_span) =>
-                    closure(ClosureParts::new(&decl, &block, e.id, e.span, &e.attrs)),
+                ast::ExprClosure(_, ref decl, block, _fn_decl_span) =>
+                    closure(ClosureParts::new(&decl, block, e.id, e.span, &e.attrs)),
                 _ => bug!("expr FnLikeNode that is not fn-like"),
             },
             _ => bug!("other FnLikeNode that is not fn-like"),
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index 26fd2b736a4..c46c8f044e0 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -10,7 +10,7 @@
 
 use super::*;
 
-use hir::intravisit::Visitor;
+use hir::intravisit::{Visitor, NestedVisitorMap};
 use hir::def_id::DefId;
 use middle::cstore::InlinedItem;
 use std::iter::repeat;
@@ -91,7 +91,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
     /// deep walking so that we walk nested items in the context of
     /// their outer items.
 
-    fn nested_visit_map(&mut self) -> Option<&map::Map<'ast>> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'ast> {
         panic!("visit_nested_xxx must be manually implemented in this visitor")
     }
 
@@ -106,6 +106,10 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
         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_item(&mut self, i: &'ast Item) {
         debug!("visit_item: {:?}", i);
 
@@ -209,7 +213,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
     }
 
     fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
-                b: &'ast Expr, s: Span, id: NodeId) {
+                b: ExprId, s: Span, id: NodeId) {
         assert_eq!(self.parent_node, id);
         intravisit::walk_fn(self, fk, fd, b, s, id);
     }
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index a08060e7927..273094b735c 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -11,7 +11,7 @@
 use hir::map::definitions::*;
 
 use hir;
-use hir::intravisit;
+use hir::intravisit::{self, Visitor, NestedVisitorMap};
 use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
 
 use middle::cstore::InlinedItem;
@@ -326,7 +326,18 @@ impl<'a> visit::Visitor for DefCollector<'a> {
 }
 
 // We walk the HIR rather than the AST when reading items from metadata.
-impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
+impl<'ast> Visitor<'ast> for DefCollector<'ast> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'ast> {
+        // note however that we override `visit_body` below
+        NestedVisitorMap::None
+    }
+
+    fn visit_body(&mut self, id: hir::ExprId) {
+        if let Some(krate) = self.hir_crate {
+            self.visit_expr(krate.expr(id));
+        }
+    }
+
     fn visit_item(&mut self, i: &'ast hir::Item) {
         debug!("visit_item: {:?}", i);
 
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index b9763e6ea0d..434e34e7003 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -18,7 +18,6 @@ pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
 use dep_graph::{DepGraph, DepNode};
 
 use middle::cstore::InlinedItem;
-use middle::cstore::InlinedItem as II;
 use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
 
 use syntax::abi::Abi;
@@ -61,6 +60,8 @@ pub enum Node<'ast> {
     NodeLifetime(&'ast Lifetime),
     NodeTyParam(&'ast TyParam),
     NodeVisibility(&'ast Visibility),
+
+    NodeInlinedItem(&'ast InlinedItem),
 }
 
 /// Represents an entry and its parent NodeID.
@@ -120,6 +121,8 @@ impl<'ast> MapEntry<'ast> {
             NodeLifetime(n) => EntryLifetime(p, n),
             NodeTyParam(n) => EntryTyParam(p, n),
             NodeVisibility(n) => EntryVisibility(p, n),
+
+            NodeInlinedItem(n) => RootInlinedParent(n),
         }
     }
 
@@ -168,6 +171,7 @@ impl<'ast> MapEntry<'ast> {
             EntryLifetime(_, n) => NodeLifetime(n),
             EntryTyParam(_, n) => NodeTyParam(n),
             EntryVisibility(_, n) => NodeVisibility(n),
+            RootInlinedParent(n) => NodeInlinedItem(n),
             _ => return None
         })
     }
@@ -252,18 +256,36 @@ impl<'ast> Map<'ast> {
         let map = self.map.borrow();
         let mut id = id0;
         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);
                         assert!(!self.is_inlined_def_id(def_id));
+
+                        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) {
+                                return DepNode::HirBody(def_id);
+                            }
+                        }
                         return DepNode::Hir(def_id);
                     }
 
-                    EntryImplItem(..) => {
+                    EntryImplItem(_, item) => {
                         let def_id = self.local_def_id(id);
                         assert!(!self.is_inlined_def_id(def_id));
+
+                        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) {
+                                return DepNode::HirBody(def_id);
+                            }
+                        }
                         return DepNode::Hir(def_id);
                     }
 
@@ -271,7 +293,6 @@ impl<'ast> Map<'ast> {
                     EntryTraitItem(p, _) |
                     EntryVariant(p, _) |
                     EntryField(p, _) |
-                    EntryExpr(p, _) |
                     EntryStmt(p, _) |
                     EntryTy(p, _) |
                     EntryTraitRef(p, _) |
@@ -284,6 +305,11 @@ impl<'ast> Map<'ast> {
                     EntryVisibility(p, _) =>
                         id = p,
 
+                    EntryExpr(p, _) => {
+                        last_expr = Some(id);
+                        id = p;
+                    }
+
                     RootCrate =>
                         return DepNode::Krate,
 
@@ -328,12 +354,8 @@ impl<'ast> Map<'ast> {
                     EntryVisibility(p, _) =>
                         id = p,
 
-                    RootInlinedParent(parent) => match *parent {
-                        InlinedItem::Item(def_id, _) |
-                        InlinedItem::TraitItem(def_id, _) |
-                        InlinedItem::ImplItem(def_id, _) =>
-                            return DepNode::MetaData(def_id)
-                    },
+                    RootInlinedParent(parent) =>
+                        return DepNode::MetaData(parent.def_id),
 
                     RootCrate =>
                         bug!("node {} has crate ancestor but is inlined", id0),
@@ -345,6 +367,29 @@ 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.borrow().len()
     }
@@ -556,8 +601,7 @@ impl<'ast> Map<'ast> {
     pub fn get_parent_did(&self, id: NodeId) -> DefId {
         let parent = self.get_parent(id);
         match self.find_entry(parent) {
-            Some(RootInlinedParent(&II::TraitItem(did, _))) |
-            Some(RootInlinedParent(&II::ImplItem(did, _))) => did,
+            Some(RootInlinedParent(ii)) => ii.def_id,
             _ => self.local_def_id(parent)
         }
     }
@@ -655,6 +699,10 @@ impl<'ast> Map<'ast> {
         }
     }
 
+    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) {
@@ -958,6 +1006,8 @@ impl<'a> NodePrinter for pprust::State<'a> {
             // printing.
             NodeLocal(_)       => bug!("cannot print isolated Local"),
             NodeStructCtor(_)  => bug!("cannot print isolated StructCtor"),
+
+            NodeInlinedItem(_) => bug!("cannot print inlined item"),
         }
     }
 }
@@ -1071,6 +1121,9 @@ 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 d494299a3c3..4fd8f96ba04 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -33,6 +33,7 @@ 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 syntax_pos::{mk_sp, Span, ExpnId, DUMMY_SP};
 use syntax::codemap::{self, respan, Spanned};
@@ -428,6 +429,7 @@ pub struct Crate {
     pub items: BTreeMap<NodeId, Item>,
 
     pub impl_items: BTreeMap<ImplItemId, ImplItem>,
+    pub exprs: FnvHashMap<ExprId, Expr>,
 }
 
 impl Crate {
@@ -458,6 +460,10 @@ impl Crate {
             visitor.visit_impl_item(impl_item);
         }
     }
+
+    pub fn expr(&self, id: ExprId) -> &Expr {
+        &self.exprs[&id]
+    }
 }
 
 /// A macro definition, in this crate or imported from another.
@@ -846,6 +852,15 @@ pub enum UnsafeSource {
     UserProvided,
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct ExprId(NodeId);
+
+impl ExprId {
+    pub fn node_id(self) -> NodeId {
+        self.0
+    }
+}
+
 /// An expression
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
 pub struct Expr {
@@ -855,6 +870,12 @@ 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))
@@ -914,7 +935,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>, P<Expr>, Span),
+    ExprClosure(CaptureClause, P<FnDecl>, ExprId, Span),
     /// A block (`{ ... }`)
     ExprBlock(P<Block>),
 
@@ -1068,7 +1089,7 @@ pub enum TraitItem_ {
     /// must contain a value)
     ConstTraitItem(P<Ty>, Option<P<Expr>>),
     /// A method with an optional body
-    MethodTraitItem(MethodSig, Option<P<Expr>>),
+    MethodTraitItem(MethodSig, Option<ExprId>),
     /// An associated type with (possibly empty) bounds and optional concrete
     /// type
     TypeTraitItem(TyParamBounds, Option<P<Ty>>),
@@ -1101,7 +1122,7 @@ pub enum ImplItemKind {
     /// of the expression
     Const(P<Ty>, P<Expr>),
     /// A method implementation with the given signature and body
-    Method(MethodSig, P<Expr>),
+    Method(MethodSig, ExprId),
     /// An associated type
     Type(P<Ty>),
 }
@@ -1546,7 +1567,7 @@ pub enum Item_ {
     /// A `const` item
     ItemConst(P<Ty>, P<Expr>),
     /// A function declaration
-    ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, P<Expr>),
+    ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, ExprId),
     /// A module
     ItemMod(Mod),
     /// An external module
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 31a85391193..74920b13280 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -644,6 +644,15 @@ impl<'a> State<'a> {
         }
     }
 
+    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()?;
@@ -729,7 +738,7 @@ impl<'a> State<'a> {
                 word(&mut self.s, " ")?;
                 self.end()?; // need to close a box
                 self.end()?; // need to close a box
-                self.print_expr(&body)?;
+                self.print_expr_id(body)?;
             }
             hir::ItemMod(ref _mod) => {
                 self.head(&visibility_qualified(&item.vis, "mod"))?;
@@ -1020,7 +1029,7 @@ impl<'a> State<'a> {
                     self.nbsp()?;
                     self.end()?; // need to close a box
                     self.end()?; // need to close a box
-                    self.print_expr(body)?;
+                    self.print_expr_id(body)?;
                 } else {
                     word(&mut self.s, ";")?;
                 }
@@ -1065,7 +1074,7 @@ impl<'a> State<'a> {
                 self.nbsp()?;
                 self.end()?; // need to close a box
                 self.end()?; // need to close a box
-                self.print_expr(body)?;
+                self.print_expr_id(body)?;
             }
             hir::ImplItemKind::Type(ref ty) => {
                 self.print_associated_type(ii.name, None, Some(ty))?;
@@ -1432,7 +1441,7 @@ impl<'a> State<'a> {
                 space(&mut self.s)?;
 
                 // this is a bare expression
-                self.print_expr(body)?;
+                self.print_expr_id(body)?;
                 self.end()?; // need to close a box
 
                 // a box will be closed by print_expr, but we didn't want an overall
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 41c8d413486..fba4f35074d 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -719,10 +719,10 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
         }
     }
 
-    fn visit_ids<F>(&mut self, f: F)
-        where F: FnOnce(&mut IdVisitor)
+    fn visit_ids<'b, F: 'b>(&'b mut self, f: F)
+        where F: FnOnce(&mut IdVisitor<'b, 'a, 'tcx>)
     {
-        let mut v = IdVisitor {
+        let mut v = IdVisitor::<'b, 'a, 'tcx> {
             cx: self
         };
         f(&mut v);
@@ -791,8 +791,8 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
     /// Because lints are scoped lexically, we want to walk nested
     /// items in the context of the outer item, so enable
     /// deep-walking.
-    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
-        Some(&self.tcx.map)
+    fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'tcx> {
+        hir_visit::NestedVisitorMap::All(&self.tcx.map)
     }
 
     fn visit_item(&mut self, it: &'tcx hir::Item) {
@@ -835,9 +835,10 @@ 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: &'tcx hir::Expr, span: Span, id: ast::NodeId) {
+                body_id: hir::ExprId, span: Span, id: ast::NodeId) {
+        let body = self.tcx.map.expr(body_id);
         run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
-        hir_visit::walk_fn(self, 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);
     }
 
@@ -1107,7 +1108,11 @@ struct IdVisitor<'a, 'b: 'a, 'tcx: 'a+'b> {
 }
 
 // Output any lints that were previously added to the session.
-impl<'a, 'b, 'tcx, 'v> hir_visit::Visitor<'v> for IdVisitor<'a, 'b, 'tcx> {
+impl<'a, 'b, 'tcx> hir_visit::Visitor<'tcx> for IdVisitor<'a, 'b, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'tcx> {
+        hir_visit::NestedVisitorMap::OnlyBodies(&self.cx.tcx.map)
+    }
+
     fn visit_id(&mut self, id: ast::NodeId) {
         if let Some(lints) = self.cx.sess().lints.borrow_mut().remove(&id) {
             debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints);
@@ -1117,12 +1122,12 @@ impl<'a, 'b, 'tcx, 'v> hir_visit::Visitor<'v> for IdVisitor<'a, 'b, 'tcx> {
         }
     }
 
-    fn visit_trait_item(&mut self, _ti: &hir::TraitItem) {
+    fn visit_trait_item(&mut self, _ti: &'tcx hir::TraitItem) {
         // Do not recurse into trait or impl items automatically. These are
         // processed separately by calling hir_visit::walk_trait_item()
     }
 
-    fn visit_impl_item(&mut self, _ii: &hir::ImplItem) {
+    fn visit_impl_item(&mut self, _ii: &'tcx hir::ImplItem) {
         // See visit_trait_item()
     }
 }
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 0867e75b9ca..d055506a382 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -137,18 +137,96 @@ pub struct NativeLibrary {
 /// 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 enum InlinedItem {
-    Item(DefId /* def-id in source crate */, P<hir::Item>),
-    TraitItem(DefId /* impl id */, P<hir::TraitItem>),
-    ImplItem(DefId /* impl id */, P<hir::ImplItem>)
+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);
+    }
 }
 
-/// A borrowed version of `hir::InlinedItem`.
-#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, Hash, Debug)]
-pub enum InlinedItemRef<'a> {
-    Item(DefId, &'a hir::Item),
-    TraitItem(DefId, &'a hir::TraitItem),
-    ImplItem(DefId, &'a hir::ImplItem)
+impl InlinedItem {
+    pub fn visit<'ast,V>(&'ast self, visitor: &mut V)
+        where V: Visitor<'ast>
+    {
+        visitor.visit_expr(&self.body);
+    }
 }
 
 pub enum LoadedMacro {
@@ -292,18 +370,6 @@ pub trait CrateStore<'tcx> {
     fn metadata_encoding_version(&self) -> &[u8];
 }
 
-impl InlinedItem {
-    pub fn visit<'ast,V>(&'ast self, visitor: &mut V)
-        where V: Visitor<'ast>
-    {
-        match *self {
-            InlinedItem::Item(_, ref i) => visitor.visit_item(&i),
-            InlinedItem::TraitItem(_, ref ti) => visitor.visit_trait_item(ti),
-            InlinedItem::ImplItem(_, ref ii) => visitor.visit_impl_item(ii),
-        }
-    }
-}
-
 // FIXME: find a better place for this?
 pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
     let mut err_count = 0;
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index 1ec3d0db8e0..f7a34c43ccc 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -193,6 +193,10 @@ fn build_nodeid_to_index(decl: Option<&hir::FnDecl>,
         let mut formals = Formals { entry: entry, index: index };
         intravisit::walk_fn_decl(&mut formals, decl);
         impl<'a, 'v> intravisit::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")
+            }
+
             fn visit_pat(&mut self, p: &hir::Pat) {
                 self.index.entry(p.id).or_insert(vec![]).push(self.entry);
                 intravisit::walk_pat(self, p)
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 618e2b05f13..1bf6b837fd9 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -15,7 +15,7 @@
 use dep_graph::DepNode;
 use hir::map as ast_map;
 use hir::{self, PatKind};
-use hir::intravisit::{self, Visitor};
+use hir::intravisit::{self, Visitor, NestedVisitorMap};
 use hir::itemlikevisit::ItemLikeVisitor;
 
 use middle::privacy;
@@ -175,7 +175,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
         }
     }
 
-    fn visit_node(&mut self, node: &ast_map::Node) {
+    fn visit_node(&mut self, node: &ast_map::Node<'tcx>) {
         let had_extern_repr = self.struct_has_extern_repr;
         self.struct_has_extern_repr = false;
         let had_inherited_pub_visibility = self.inherited_pub_visibility;
@@ -220,9 +220,12 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+    }
 
-    fn visit_variant_data(&mut self, def: &hir::VariantData, _: ast::Name,
+    fn visit_variant_data(&mut self, def: &'tcx hir::VariantData, _: ast::Name,
                         _: &hir::Generics, _: ast::NodeId, _: syntax_pos::Span) {
         let has_extern_repr = self.struct_has_extern_repr;
         let inherited_pub_visibility = self.inherited_pub_visibility;
@@ -234,7 +237,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
         intravisit::walk_struct_def(self, def);
     }
 
-    fn visit_expr(&mut self, expr: &hir::Expr) {
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         match expr.node {
             hir::ExprPath(ref qpath @ hir::QPath::TypeRelative(..)) => {
                 let def = self.tcx.tables().qpath_def(qpath, expr.id);
@@ -255,7 +258,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
         intravisit::walk_expr(self, expr);
     }
 
-    fn visit_arm(&mut self, arm: &hir::Arm) {
+    fn visit_arm(&mut self, arm: &'tcx hir::Arm) {
         if arm.pats.len() == 1 {
             let variants = arm.pats[0].necessary_variants();
 
@@ -271,7 +274,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
         }
     }
 
-    fn visit_pat(&mut self, pat: &hir::Pat) {
+    fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
         match pat.node {
             PatKind::Struct(hir::QPath::Resolved(_, ref path), ref fields, _) => {
                 self.handle_field_pattern_match(pat, path.def, fields);
@@ -288,7 +291,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
         self.ignore_non_const_paths = false;
     }
 
-    fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) {
+    fn visit_path(&mut self, path: &'tcx hir::Path, id: ast::NodeId) {
         self.handle_definition(id, path.def);
         intravisit::walk_path(self, path);
     }
@@ -507,8 +510,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
     /// on inner functions when the outer function is already getting
     /// an error. We could do this also by checking the parents, but
     /// this is how the code is setup and it seems harmless enough.
-    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
-        Some(&self.tcx.map)
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::All(&self.tcx.map)
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item) {
@@ -562,12 +565,12 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> {
                 }
                 intravisit::walk_expr(self, expr)
             }
-            hir::ImplItemKind::Method(_, ref body) => {
+            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");
                 }
-                intravisit::walk_expr(self, body)
+                self.visit_body(body_id)
             }
             hir::ImplItemKind::Type(..) => {}
         }
@@ -576,10 +579,12 @@ 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))|
-            hir::MethodTraitItem(_, Some(ref body)) => {
+            hir::ConstTraitItem(_, Some(ref body)) => {
                 intravisit::walk_expr(self, body)
             }
+            hir::MethodTraitItem(_, Some(body_id)) => {
+                self.visit_body(body_id)
+            }
             hir::ConstTraitItem(_, None) |
             hir::MethodTraitItem(_, None) |
             hir::TypeTraitItem(..) => {}
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index 1313a3504c0..2ec7aa4c4d9 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -21,7 +21,7 @@ use syntax::ast;
 use syntax_pos::Span;
 use hir::{self, PatKind};
 use hir::def::Def;
-use hir::intravisit::{self, FnKind, Visitor};
+use hir::intravisit::{self, FnKind, Visitor, NestedVisitorMap};
 
 #[derive(Copy, Clone)]
 struct UnsafeContext {
@@ -92,9 +92,13 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
-    fn visit_fn(&mut self, fn_kind: FnKind<'v>, fn_decl: &'v hir::FnDecl,
-                block: &'v hir::Expr, span: Span, id: ast::NodeId) {
+impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+    }
+
+    fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, fn_decl: &'tcx hir::FnDecl,
+                body_id: hir::ExprId, span: Span, id: ast::NodeId) {
 
         let (is_item_fn, is_unsafe_fn) = match fn_kind {
             FnKind::ItemFn(_, _, unsafety, ..) =>
@@ -111,12 +115,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
             self.unsafe_context = UnsafeContext::new(SafeContext)
         }
 
-        intravisit::walk_fn(self, fn_kind, fn_decl, block, span, id);
+        intravisit::walk_fn(self, fn_kind, fn_decl, body_id, span, id);
 
         self.unsafe_context = old_unsafe_context
     }
 
-    fn visit_block(&mut self, block: &hir::Block) {
+    fn visit_block(&mut self, block: &'tcx hir::Block) {
         let old_unsafe_context = self.unsafe_context;
         match block.rules {
             hir::UnsafeBlock(source) => {
@@ -155,7 +159,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
         self.unsafe_context = old_unsafe_context
     }
 
-    fn visit_expr(&mut self, expr: &hir::Expr) {
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         match expr.node {
             hir::ExprMethodCall(..) => {
                 let method_call = MethodCall::expr(expr.id);
@@ -212,7 +216,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
         intravisit::walk_expr(self, expr);
     }
 
-    fn visit_pat(&mut self, pat: &hir::Pat) {
+    fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
         if let PatKind::Struct(_, ref fields, _) = pat.node {
             if let ty::TyAdt(adt, ..) = self.tcx.tables().pat_ty(pat).sty {
                 if adt.is_union() {
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index 65aedae347a..e927843a984 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -47,6 +47,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
         find_item(item, self, at_root);
     }
 
+
     fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem) {
         // entry fn is never an impl item
     }
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index 0014d17abb7..6896c69d7db 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -19,7 +19,7 @@ use ty::layout::{LayoutError, Pointer, SizeSkeleton};
 use syntax::abi::Abi::RustIntrinsic;
 use syntax::ast;
 use syntax_pos::Span;
-use hir::intravisit::{self, Visitor, FnKind};
+use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
 use hir;
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
@@ -34,7 +34,7 @@ struct ItemVisitor<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx> ItemVisitor<'a, 'tcx> {
-    fn visit_const(&mut self, item_id: ast::NodeId, expr: &hir::Expr) {
+    fn visit_const(&mut self, item_id: ast::NodeId, expr: &'tcx hir::Expr) {
         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 {
@@ -116,9 +116,13 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for ItemVisitor<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+    }
+
     // const, static and N in [T; N].
-    fn visit_expr(&mut self, expr: &hir::Expr) {
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         self.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
             let mut visitor = ExprVisitor {
                 infcx: &infcx
@@ -127,7 +131,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
         });
     }
 
-    fn visit_trait_item(&mut self, item: &hir::TraitItem) {
+    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);
         } else {
@@ -135,7 +139,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
         }
     }
 
-    fn visit_impl_item(&mut self, item: &hir::ImplItem) {
+    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);
         } else {
@@ -143,8 +147,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
         }
     }
 
-    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
-                b: &'v hir::Expr, s: Span, id: ast::NodeId) {
+    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, "intrinsicck: closure outside of function")
         }
@@ -158,8 +162,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'gcx, 'tcx> {
-    fn visit_expr(&mut self, expr: &hir::Expr) {
+impl<'a, 'gcx, 'tcx> Visitor<'gcx> for ExprVisitor<'a, 'gcx, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
+        NestedVisitorMap::OnlyBodies(&self.infcx.tcx.map)
+    }
+
+    fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
         let def = if let hir::ExprPath(ref qpath) = expr.node {
             self.infcx.tcx.tables().qpath_def(qpath, expr.id)
         } else {
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index eb00238492e..445aed8f97d 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -128,7 +128,7 @@ use syntax_pos::Span;
 use hir::Expr;
 use hir;
 use hir::print::{expr_to_string, block_to_string};
-use hir::intravisit::{self, Visitor, FnKind};
+use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
 
 /// For use with `propagate_through_loop`.
 enum LoopKind<'a> {
@@ -182,14 +182,18 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt) -> String {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for IrMaps<'a, 'tcx> {
-    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
-                b: &'v hir::Expr, s: Span, id: NodeId) {
+impl<'a, 'tcx> Visitor<'tcx> for IrMaps<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+    }
+
+    fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
+                b: hir::ExprId, s: Span, id: NodeId) {
         visit_fn(self, fk, fd, b, s, id);
     }
-    fn visit_local(&mut self, l: &hir::Local) { visit_local(self, l); }
-    fn visit_expr(&mut self, ex: &Expr) { visit_expr(self, ex); }
-    fn visit_arm(&mut self, a: &hir::Arm) { visit_arm(self, a); }
+    fn visit_local(&mut self, l: &'tcx hir::Local) { visit_local(self, l); }
+    fn visit_expr(&mut self, ex: &'tcx Expr) { visit_expr(self, ex); }
+    fn visit_arm(&mut self, a: &'tcx hir::Arm) { visit_arm(self, a); }
 }
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
@@ -348,28 +352,32 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for Liveness<'a, 'tcx> {
-    fn visit_fn(&mut self, _: FnKind<'v>, _: &'v hir::FnDecl,
-                _: &'v hir::Expr, _: Span, _: NodeId) {
+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)
+    }
+
+    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: &hir::Local) {
+    fn visit_local(&mut self, l: &'tcx hir::Local) {
         check_local(self, l);
     }
-    fn visit_expr(&mut self, ex: &Expr) {
+    fn visit_expr(&mut self, ex: &'tcx Expr) {
         check_expr(self, ex);
     }
-    fn visit_arm(&mut self, a: &hir::Arm) {
+    fn visit_arm(&mut self, a: &'tcx hir::Arm) {
         check_arm(self, a);
     }
 }
 
-fn visit_fn(ir: &mut IrMaps,
-            fk: FnKind,
-            decl: &hir::FnDecl,
-            body: &hir::Expr,
-            sp: Span,
-            id: ast::NodeId) {
+fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
+                          fk: FnKind<'tcx>,
+                          decl: &'tcx hir::FnDecl,
+                          body_id: hir::ExprId,
+                          sp: Span,
+                          id: ast::NodeId) {
     debug!("visit_fn");
 
     // swap in a new set of IR maps for this function body:
@@ -387,7 +395,7 @@ fn visit_fn(ir: &mut IrMaps,
 
     // gather up the various local variables, significant expressions,
     // and so forth:
-    intravisit::walk_fn(&mut fn_maps, fk, decl, body, sp, id);
+    intravisit::walk_fn(&mut fn_maps, fk, decl, body_id, sp, id);
 
     // Special nodes and variables:
     // - exit_ln represents the end of the fn, either by return or panic
@@ -400,6 +408,8 @@ fn visit_fn(ir: &mut IrMaps,
         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);
@@ -410,7 +420,7 @@ fn visit_fn(ir: &mut IrMaps,
     lsets.warn_about_unused_args(decl, entry_ln);
 }
 
-fn visit_local(ir: &mut IrMaps, local: &hir::Local) {
+fn visit_local<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, local: &'tcx hir::Local) {
     local.pat.each_binding(|_, p_id, sp, path1| {
         debug!("adding local variable {}", p_id);
         let name = path1.node;
@@ -423,7 +433,7 @@ fn visit_local(ir: &mut IrMaps, local: &hir::Local) {
     intravisit::walk_local(ir, local);
 }
 
-fn visit_arm(ir: &mut IrMaps, arm: &hir::Arm) {
+fn visit_arm<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, arm: &'tcx hir::Arm) {
     for pat in &arm.pats {
         pat.each_binding(|bm, p_id, sp, path1| {
             debug!("adding local variable {} from match with bm {:?}",
@@ -439,7 +449,7 @@ fn visit_arm(ir: &mut IrMaps, arm: &hir::Arm) {
     intravisit::walk_arm(ir, arm);
 }
 
-fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
+fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) {
     match expr.node {
       // live nodes required for uses or definitions of variables:
       hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
@@ -923,7 +933,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
               self.propagate_through_expr(&e, succ)
           }
 
-          hir::ExprClosure(.., ref blk, _) => {
+          hir::ExprClosure(.., blk_id, _) => {
               debug!("{} is an ExprClosure",
                      expr_to_string(expr));
 
@@ -932,7 +942,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
               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, 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.
@@ -1354,7 +1364,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 // _______________________________________________________________________
 // Checking for error conditions
 
-fn check_local(this: &mut Liveness, local: &hir::Local) {
+fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local) {
     match local.init {
         Some(_) => {
             this.warn_about_unused_or_dead_vars_in_pat(&local.pat);
@@ -1369,7 +1379,7 @@ fn check_local(this: &mut Liveness, local: &hir::Local) {
     intravisit::walk_local(this, local);
 }
 
-fn check_arm(this: &mut Liveness, arm: &hir::Arm) {
+fn check_arm<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, arm: &'tcx hir::Arm) {
     // only consider the first pattern; any later patterns must have
     // the same bindings, and we also consider the first pattern to be
     // the "authoritative" set of ids
@@ -1379,7 +1389,7 @@ fn check_arm(this: &mut Liveness, arm: &hir::Arm) {
     intravisit::walk_arm(this, arm);
 }
 
-fn check_expr(this: &mut Liveness, expr: &Expr) {
+fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
     match expr.node {
       hir::ExprAssign(ref l, _) => {
         this.check_lvalue(&l);
@@ -1469,7 +1479,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         }
     }
 
-    fn check_lvalue(&mut self, expr: &Expr) {
+    fn check_lvalue(&mut self, expr: &'tcx Expr) {
         match expr.node {
             hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
                 if let Def::Local(def_id) = path.def {
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 8d3e734f8c3..4c3b102e540 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -705,7 +705,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             };
 
             match fn_expr.node {
-                hir::ExprClosure(.., ref body, _) => body.id,
+                hir::ExprClosure(.., body_id, _) => body_id.node_id(),
                 _ => bug!()
             }
         };
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index b17d41e0fa5..9798b2d587d 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -28,7 +28,7 @@ use syntax::abi::Abi;
 use syntax::ast;
 use syntax::attr;
 use hir;
-use hir::intravisit::Visitor;
+use hir::intravisit::{Visitor, NestedVisitorMap};
 use hir::itemlikevisit::ItemLikeVisitor;
 use hir::intravisit;
 
@@ -88,8 +88,12 @@ struct ReachableContext<'a, 'tcx: 'a> {
     any_library: bool,
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
-    fn visit_expr(&mut self, expr: &hir::Expr) {
+impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+    }
+
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         let def = match expr.node {
             hir::ExprPath(ref qpath) => {
                 Some(self.tcx.tables().qpath_def(qpath, expr.id))
@@ -216,7 +220,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
         }
     }
 
-    fn propagate_node(&mut self, node: &ast_map::Node,
+    fn propagate_node(&mut self, node: &ast_map::Node<'tcx>,
                       search_item: ast::NodeId) {
         if !self.any_library {
             // If we are building an executable, only explicitly extern
@@ -244,9 +248,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
         match *node {
             ast_map::NodeItem(item) => {
                 match item.node {
-                    hir::ItemFn(.., ref body) => {
+                    hir::ItemFn(.., body) => {
                         if item_might_be_inlined(&item) {
-                            self.visit_expr(body);
+                            self.visit_body(body);
                         }
                     }
 
@@ -274,10 +278,12 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                     hir::MethodTraitItem(_, None) => {
                         // Keep going, nothing to get exported
                     }
-                    hir::ConstTraitItem(_, Some(ref body)) |
-                    hir::MethodTraitItem(_, Some(ref body)) => {
+                    hir::ConstTraitItem(_, Some(ref body)) => {
                         self.visit_expr(body);
                     }
+                    hir::MethodTraitItem(_, Some(body_id)) => {
+                        self.visit_body(body_id);
+                    }
                     hir::TypeTraitItem(..) => {}
                 }
             }
@@ -286,10 +292,10 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                     hir::ImplItemKind::Const(_, ref expr) => {
                         self.visit_expr(&expr);
                     }
-                    hir::ImplItemKind::Method(ref sig, ref 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_expr(body)
+                            self.visit_body(body)
                         }
                     }
                     hir::ImplItemKind::Type(_) => {}
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 0dbde2d21ca..05fa619ce41 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -31,7 +31,7 @@ use syntax::ast::{self, NodeId};
 use syntax_pos::Span;
 
 use hir;
-use hir::intravisit::{self, Visitor, FnKind};
+use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
 use hir::{Block, Item, FnDecl, Arm, Pat, PatKind, Stmt, Expr, Local};
 
 #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable,
@@ -302,7 +302,7 @@ pub struct Context {
     parent: CodeExtent
 }
 
-struct RegionResolutionVisitor<'a> {
+struct RegionResolutionVisitor<'ast: 'a, 'a> {
     sess: &'a Session,
 
     // Generated maps:
@@ -310,6 +310,8 @@ struct RegionResolutionVisitor<'a> {
 
     cx: Context,
 
+    map: &'a ast_map::Map<'ast>,
+
     /// `terminating_scopes` is a set containing the ids of each
     /// statement, or conditional/repeating expression. These scopes
     /// are calling "terminating scopes" because, when attempting to
@@ -660,7 +662,7 @@ fn record_var_lifetime(visitor: &mut RegionResolutionVisitor,
     }
 }
 
-fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &hir::Block) {
+fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, blk: &'tcx hir::Block) {
     debug!("resolve_block(blk.id={:?})", blk.id);
 
     let prev_cx = visitor.cx;
@@ -731,7 +733,7 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &hir::Block) {
     visitor.cx = prev_cx;
 }
 
-fn resolve_arm(visitor: &mut RegionResolutionVisitor, arm: &hir::Arm) {
+fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, arm: &'tcx hir::Arm) {
     visitor.terminating_scopes.insert(arm.body.id);
 
     if let Some(ref expr) = arm.guard {
@@ -741,7 +743,7 @@ fn resolve_arm(visitor: &mut RegionResolutionVisitor, arm: &hir::Arm) {
     intravisit::walk_arm(visitor, arm);
 }
 
-fn resolve_pat(visitor: &mut RegionResolutionVisitor, pat: &hir::Pat) {
+fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, pat: &'tcx hir::Pat) {
     visitor.new_node_extent(pat.id);
 
     // If this is a binding then record the lifetime of that binding.
@@ -752,7 +754,7 @@ fn resolve_pat(visitor: &mut RegionResolutionVisitor, pat: &hir::Pat) {
     intravisit::walk_pat(visitor, pat);
 }
 
-fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &hir::Stmt) {
+fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, stmt: &'tcx hir::Stmt) {
     let stmt_id = stmt.node.id();
     debug!("resolve_stmt(stmt.id={:?})", stmt_id);
 
@@ -770,7 +772,7 @@ fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &hir::Stmt) {
     visitor.cx.parent = prev_parent;
 }
 
-fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &hir::Expr) {
+fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, expr: &'tcx hir::Expr) {
     debug!("resolve_expr(expr.id={:?})", expr.id);
 
     let expr_extent = visitor.new_node_extent_with_dtor(expr.id);
@@ -848,7 +850,8 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &hir::Expr) {
     visitor.cx = prev_cx;
 }
 
-fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &hir::Local) {
+fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
+                           local: &'tcx hir::Local) {
     debug!("resolve_local(local.id={:?},local.init={:?})",
            local.id,local.init.is_some());
 
@@ -1063,7 +1066,7 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &hir::Local) {
     }
 }
 
-fn resolve_item(visitor: &mut RegionResolutionVisitor, item: &hir::Item) {
+fn resolve_item<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, item: &'tcx hir::Item) {
     // Items create a new outer block scope as far as we're concerned.
     let prev_cx = visitor.cx;
     let prev_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet());
@@ -1078,38 +1081,38 @@ fn resolve_item(visitor: &mut RegionResolutionVisitor, item: &hir::Item) {
     visitor.terminating_scopes = prev_ts;
 }
 
-fn resolve_fn(visitor: &mut RegionResolutionVisitor,
-              kind: FnKind,
-              decl: &hir::FnDecl,
-              body: &hir::Expr,
-              sp: Span,
-              id: ast::NodeId) {
+fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
+                        kind: FnKind<'tcx>,
+                        decl: &'tcx hir::FnDecl,
+                        body_id: hir::ExprId,
+                        sp: Span,
+                        id: ast::NodeId) {
     debug!("region::resolve_fn(id={:?}, \
                                span={:?}, \
                                body.id={:?}, \
                                cx.parent={:?})",
            id,
            visitor.sess.codemap().span_to_string(sp),
-           body.id,
+           body_id,
            visitor.cx.parent);
 
     visitor.cx.parent = visitor.new_code_extent(
-        CodeExtentData::CallSiteScope { fn_id: id, body_id: body.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 });
+        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, 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);
+    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),
+        root_id: Some(body_id.node_id()),
         parent: ROOT_CODE_EXTENT,
         var_parent: fn_decl_scope,
     };
@@ -1119,18 +1122,18 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor,
 
     // The body of the every fn is a root scope.
     visitor.cx = Context {
-        root_id: Some(body.id),
+        root_id: Some(body_id.node_id()),
         parent: fn_decl_scope,
         var_parent: fn_decl_scope
     };
-    visitor.visit_expr(body);
+    visitor.visit_body(body_id);
 
     // Restore context we had at the start.
     visitor.cx = outer_cx;
     visitor.terminating_scopes = outer_ts;
 }
 
-impl<'a> RegionResolutionVisitor<'a> {
+impl<'ast, 'a> RegionResolutionVisitor<'ast, 'a> {
     /// Records the current parent (if any) as the parent of `child_scope`.
     fn new_code_extent(&mut self, child_scope: CodeExtentData) -> CodeExtent {
         self.region_maps.intern_code_extent(child_scope, self.cx.parent)
@@ -1166,42 +1169,46 @@ impl<'a> RegionResolutionVisitor<'a> {
     }
 }
 
-impl<'a, 'v> Visitor<'v> for RegionResolutionVisitor<'a> {
-    fn visit_block(&mut self, b: &Block) {
+impl<'ast, 'a> Visitor<'ast> for RegionResolutionVisitor<'ast, 'a> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'ast> {
+        NestedVisitorMap::OnlyBodies(&self.map)
+    }
+
+    fn visit_block(&mut self, b: &'ast Block) {
         resolve_block(self, b);
     }
 
-    fn visit_item(&mut self, i: &Item) {
+    fn visit_item(&mut self, i: &'ast Item) {
         resolve_item(self, i);
     }
 
-    fn visit_impl_item(&mut self, ii: &hir::ImplItem) {
+    fn visit_impl_item(&mut self, ii: &'ast hir::ImplItem) {
         intravisit::walk_impl_item(self, ii);
         self.create_item_scope_if_needed(ii.id);
     }
 
-    fn visit_trait_item(&mut self, ti: &hir::TraitItem) {
+    fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
         intravisit::walk_trait_item(self, ti);
         self.create_item_scope_if_needed(ti.id);
     }
 
-    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl,
-                b: &'v Expr, s: Span, n: NodeId) {
+    fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl,
+                b: hir::ExprId, s: Span, n: NodeId) {
         resolve_fn(self, fk, fd, b, s, n);
     }
-    fn visit_arm(&mut self, a: &Arm) {
+    fn visit_arm(&mut self, a: &'ast Arm) {
         resolve_arm(self, a);
     }
-    fn visit_pat(&mut self, p: &Pat) {
+    fn visit_pat(&mut self, p: &'ast Pat) {
         resolve_pat(self, p);
     }
-    fn visit_stmt(&mut self, s: &Stmt) {
+    fn visit_stmt(&mut self, s: &'ast Stmt) {
         resolve_stmt(self, s);
     }
-    fn visit_expr(&mut self, ex: &Expr) {
+    fn visit_expr(&mut self, ex: &'ast Expr) {
         resolve_expr(self, ex);
     }
-    fn visit_local(&mut self, l: &Local) {
+    fn visit_local(&mut self, l: &'ast Local) {
         resolve_local(self, l);
     }
 }
@@ -1228,6 +1235,7 @@ pub fn resolve_crate(sess: &Session, map: &ast_map::Map) -> RegionMaps {
         let mut visitor = RegionResolutionVisitor {
             sess: sess,
             region_maps: &maps,
+            map: map,
             cx: Context {
                 root_id: None,
                 parent: ROOT_CODE_EXTENT,
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index d07062f98a9..c5b03a4a32a 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -34,7 +34,7 @@ use util::nodemap::NodeMap;
 use rustc_data_structures::fx::FxHashSet;
 use hir;
 use hir::print::lifetime_to_string;
-use hir::intravisit::{self, Visitor, FnKind};
+use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
 pub enum DefRegion {
@@ -132,8 +132,8 @@ pub fn krate(sess: &Session,
 impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     // Override the nested functions -- lifetimes follow lexical scope,
     // so it's convenient to walk the tree in lexical order.
-    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
-        Some(&self.hir_map)
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::All(&self.hir_map)
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item) {
@@ -206,7 +206,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self, fk: FnKind<'tcx>, decl: &'tcx hir::FnDecl,
-                b: &'tcx hir::Expr, s: Span, fn_id: ast::NodeId) {
+                b: hir::ExprId, s: Span, fn_id: ast::NodeId) {
         match fk {
             FnKind::ItemFn(_, generics, ..) => {
                 self.visit_early_late(fn_id,decl, generics, |this| {
@@ -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::Expr) {
+fn extract_labels(ctxt: &mut LifetimeContext, b: hir::ExprId) {
     struct GatherLabels<'a> {
         sess: &'a Session,
         scope: Scope<'a>,
@@ -419,10 +419,14 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Expr) {
         scope: ctxt.scope,
         labels_in_fn: &mut ctxt.labels_in_fn,
     };
-    gather.visit_expr(b);
+    gather.visit_expr(ctxt.hir_map.expr(b));
     return;
 
     impl<'v, 'a> Visitor<'v> for GatherLabels<'a> {
+        fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
+            NestedVisitorMap::None
+        }
+
         fn visit_expr(&mut self, ex: &'v hir::Expr) {
             // do not recurse into closures defined in the block
             // since they are treated as separate fns from the POV of
@@ -497,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: &'tcx hir::Expr,
+                             fb: hir::ExprId,
                              _span: Span,
                              fn_id: ast::NodeId) {
         match fk {
@@ -518,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.id, s: self.scope },
-                  |_old_scope, this| this.visit_expr(fb))
+        self.with(FnScope { fn_id: fn_id, body_id: fb.node_id(), s: self.scope },
+                  |_old_scope, this| this.visit_body(fb))
     }
 
     // FIXME(#37666) this works around a limitation in the region inferencer
@@ -938,6 +942,10 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
     }
 
     impl<'v> Visitor<'v> for ConstrainedCollector {
+        fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
+            NestedVisitorMap::None
+        }
+
         fn visit_ty(&mut self, ty: &'v hir::Ty) {
             match ty.node {
                 hir::TyPath(hir::QPath::Resolved(Some(_), _)) |
@@ -975,6 +983,10 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
     }
 
     impl<'v> Visitor<'v> for AllCollector {
+        fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
+            NestedVisitorMap::None
+        }
+
         fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
             self.regions.insert(lifetime_ref.name);
         }
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index f5e18e13465..f3890f1c3b7 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -30,8 +30,7 @@ use util::nodemap::{DefIdMap, FxHashSet, FxHashMap};
 
 use hir;
 use hir::{Item, Generics, StructField, Variant};
-use hir::intravisit::{self, Visitor};
-use hir::itemlikevisit::DeepVisitor;
+use hir::intravisit::{self, Visitor, NestedVisitorMap};
 
 use std::mem::replace;
 use std::cmp::Ordering;
@@ -234,8 +233,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
     /// Because stability levels are scoped lexically, we want to walk
     /// nested items in the context of the outer item, so enable
     /// deep-walking.
-    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
-        Some(&self.tcx.map)
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::All(&self.tcx.map)
     }
 
     fn visit_item(&mut self, i: &'tcx Item) {
@@ -326,8 +325,12 @@ impl<'a, 'tcx: 'a> MissingStabilityAnnotations<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for MissingStabilityAnnotations<'a, 'tcx> {
-    fn visit_item(&mut self, i: &Item) {
+impl<'a, 'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+    }
+
+    fn visit_item(&mut self, i: &'tcx Item) {
         match i.node {
             // Inherent impls and foreign modules serve only as containers for other items,
             // they don't have their own stability. They still can be annotated as unstable
@@ -341,12 +344,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MissingStabilityAnnotations<'a, 'tcx> {
         intravisit::walk_item(self, i)
     }
 
-    fn visit_trait_item(&mut self, ti: &hir::TraitItem) {
+    fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
         self.check_missing_stability(ti.id, ti.span);
         intravisit::walk_trait_item(self, ti);
     }
 
-    fn visit_impl_item(&mut self, ii: &hir::ImplItem) {
+    fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
         let impl_def_id = self.tcx.map.local_def_id(self.tcx.map.get_parent(ii.id));
         if self.tcx.impl_trait_ref(impl_def_id).is_none() {
             self.check_missing_stability(ii.id, ii.span);
@@ -354,22 +357,22 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MissingStabilityAnnotations<'a, 'tcx> {
         intravisit::walk_impl_item(self, ii);
     }
 
-    fn visit_variant(&mut self, var: &Variant, g: &Generics, item_id: NodeId) {
+    fn visit_variant(&mut self, var: &'tcx Variant, g: &'tcx Generics, item_id: NodeId) {
         self.check_missing_stability(var.node.data.id(), var.span);
         intravisit::walk_variant(self, var, g, item_id);
     }
 
-    fn visit_struct_field(&mut self, s: &StructField) {
+    fn visit_struct_field(&mut self, s: &'tcx StructField) {
         self.check_missing_stability(s.id, s.span);
         intravisit::walk_struct_field(self, s);
     }
 
-    fn visit_foreign_item(&mut self, i: &hir::ForeignItem) {
+    fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem) {
         self.check_missing_stability(i.id, i.span);
         intravisit::walk_foreign_item(self, i);
     }
 
-    fn visit_macro_def(&mut self, md: &hir::MacroDef) {
+    fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) {
         if md.imported_from.is_none() {
             self.check_missing_stability(md.id, md.span);
         }
@@ -425,8 +428,7 @@ impl<'a, 'tcx> Index<'tcx> {
 /// features and possibly prints errors.
 pub fn check_unstable_api_usage<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let mut checker = Checker { tcx: tcx };
-    tcx.visit_all_item_likes_in_krate(DepNode::StabilityCheck,
-                                      &mut DeepVisitor::new(&mut checker));
+    tcx.visit_all_item_likes_in_krate(DepNode::StabilityCheck, &mut checker.as_deep_visitor());
 }
 
 struct Checker<'a, 'tcx: 'a> {
@@ -534,6 +536,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
+    /// Because stability levels are scoped lexically, we want to walk
+    /// nested items in the context of the outer item, so enable
+    /// deep-walking.
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+    }
+
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         match item.node {
             hir::ItemExternCrate(_) => {
@@ -641,7 +650,7 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         };
         missing.check_missing_stability(ast::CRATE_NODE_ID, krate.span);
         intravisit::walk_crate(&mut missing, krate);
-        krate.visit_all_item_likes(&mut DeepVisitor::new(&mut missing));
+        krate.visit_all_item_likes(&mut missing.as_deep_visitor());
     }
 
     let ref declared_lib_features = sess.features.borrow().declared_lib_features;
diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs
index 30690c09919..c6df1497e68 100644
--- a/src/librustc/middle/weak_lang_items.rs
+++ b/src/librustc/middle/weak_lang_items.rs
@@ -18,7 +18,7 @@ use rustc_back::PanicStrategy;
 use syntax::ast;
 use syntax::symbol::Symbol;
 use syntax_pos::Span;
-use hir::intravisit::Visitor;
+use hir::intravisit::{Visitor, NestedVisitorMap};
 use hir::intravisit;
 use hir;
 
@@ -125,6 +125,10 @@ impl<'a> Context<'a> {
 }
 
 impl<'a, 'v> Visitor<'v> for Context<'a> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
+        NestedVisitorMap::None
+    }
+
     fn visit_foreign_item(&mut self, i: &hir::ForeignItem) {
         if let Some(lang_item) = lang_items::extract(&i.attrs) {
             self.register(&lang_item.as_str(), i.span);
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 844fc58cec3..9a92e9e70fe 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1208,7 +1208,7 @@ 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.id))
+                            tcx.region_maps.call_site_extent(id, body.node_id()))
                     }
                 }
             }
@@ -1227,9 +1227,9 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
                         // 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(ref body) = *body {
+                        let extent = if let Some(body_id) = *body {
                             // default impl: use call_site extent as free_id_outlive bound.
-                            tcx.region_maps.call_site_extent(id, body.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)
@@ -1243,14 +1243,14 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
             }
             Some(ast_map::NodeItem(item)) => {
                 match item.node {
-                    hir::ItemFn(.., ref body) => {
+                    hir::ItemFn(.., body_id) => {
                         // We assume this is a function.
                         let fn_def_id = tcx.map.local_def_id(id);
 
                         tcx.construct_parameter_environment(
                             item.span,
                             fn_def_id,
-                            tcx.region_maps.call_site_extent(id, body.id))
+                            tcx.region_maps.call_site_extent(id, body_id.node_id()))
                     }
                     hir::ItemEnum(..) |
                     hir::ItemStruct(..) |
@@ -1280,13 +1280,13 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
             }
             Some(ast_map::NodeExpr(expr)) => {
                 // This is a convenience to allow closures to work.
-                if let hir::ExprClosure(.., ref body, _) = expr.node {
+                if let hir::ExprClosure(.., body, _) = expr.node {
                     let def_id = tcx.map.local_def_id(id);
                     let base_def_id = tcx.closure_base_def_id(def_id);
                     tcx.construct_parameter_environment(
                         expr.span,
                         base_def_id,
-                        tcx.region_maps.call_site_extent(id, body.id))
+                        tcx.region_maps.call_site_extent(id, body.node_id()))
                 } else {
                     tcx.empty_parameter_environment()
                 }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 8f2afa7f808..5d59b58b847 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -30,7 +30,7 @@ use syntax_pos::Span;
 use rustc::hir;
 use rustc::hir::Expr;
 use rustc::hir::intravisit;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
 
 use self::restrictions::RestrictionResult;
 
@@ -520,8 +520,12 @@ struct StaticInitializerCtxt<'a, 'tcx: 'a> {
     item_id: ast::NodeId
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for StaticInitializerCtxt<'a, 'tcx> {
-    fn visit_expr(&mut self, ex: &Expr) {
+impl<'a, 'tcx> Visitor<'tcx> for StaticInitializerCtxt<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.bccx.tcx.map)
+    }
+
+    fn visit_expr(&mut self, ex: &'tcx Expr) {
         if let hir::ExprAddrOf(mutbl, ref base) = ex.node {
             let param_env = ty::ParameterEnvironment::for_item(self.bccx.tcx,
                                                                self.item_id);
@@ -542,9 +546,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for StaticInitializerCtxt<'a, 'tcx> {
     }
 }
 
-pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt,
-                                          item_id: ast::NodeId,
-                                          expr: &hir::Expr) {
+pub fn gather_loans_in_static_initializer<'a, 'tcx>(bccx: &mut BorrowckCtxt<'a, 'tcx>,
+                                                    item_id: ast::NodeId,
+                                                    expr: &'tcx hir::Expr) {
 
     debug!("gather_loans_in_static_initializer(expr={:?})", expr);
 
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 5e54e333bb9..34e91e60074 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -47,7 +47,7 @@ use syntax_pos::{MultiSpan, Span};
 use errors::DiagnosticBuilder;
 
 use rustc::hir;
-use rustc::hir::intravisit::{self, Visitor, FnKind};
+use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
 
 pub mod check_loans;
 
@@ -62,9 +62,13 @@ pub struct LoanDataFlowOperator;
 
 pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>;
 
-impl<'a, 'tcx, 'v> Visitor<'v> for BorrowckCtxt<'a, 'tcx> {
-    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
-                b: &'v hir::Expr, s: Span, id: ast::NodeId) {
+impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        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) {
         match fk {
             FnKind::ItemFn(..) |
             FnKind::Method(..) => {
@@ -79,18 +83,18 @@ impl<'a, 'tcx, 'v> Visitor<'v> for BorrowckCtxt<'a, 'tcx> {
         }
     }
 
-    fn visit_item(&mut self, item: &hir::Item) {
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
         borrowck_item(self, item);
     }
 
-    fn visit_trait_item(&mut self, ti: &hir::TraitItem) {
+    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);
         }
         intravisit::walk_trait_item(self, ti);
     }
 
-    fn visit_impl_item(&mut self, ii: &hir::ImplItem) {
+    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);
         }
@@ -131,7 +135,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     }
 }
 
-fn borrowck_item(this: &mut BorrowckCtxt, item: &hir::Item) {
+fn borrowck_item<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, item: &'tcx hir::Item) {
     // Gather loans for items. Note that we don't need
     // to check loans for single expressions. The check
     // loan step is intended for things that have a data
@@ -154,15 +158,17 @@ pub struct AnalysisData<'a, 'tcx: 'a> {
     pub move_data: move_data::FlowedMoveData<'a, 'tcx>,
 }
 
-fn borrowck_fn(this: &mut BorrowckCtxt,
-               fk: FnKind,
-               decl: &hir::FnDecl,
-               body: &hir::Expr,
-               sp: Span,
-               id: ast::NodeId,
-               attributes: &[ast::Attribute]) {
+fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
+                         fk: FnKind<'tcx>,
+                         decl: &'tcx hir::FnDecl,
+                         body_id: hir::ExprId,
+                         sp: Span,
+                         id: ast::NodeId,
+                         attributes: &[ast::Attribute]) {
     debug!("borrowck_fn(id={})", id);
 
+    let body = this.tcx.map.expr(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)
@@ -191,21 +197,21 @@ fn borrowck_fn(this: &mut BorrowckCtxt,
                              decl,
                              body);
 
-    intravisit::walk_fn(this, fk, decl, body, sp, id);
+    intravisit::walk_fn(this, fk, decl, body_id, sp, id);
 }
 
 fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
-                                          fk: FnKind,
-                                          decl: &hir::FnDecl,
+                                          fk: FnKind<'tcx>,
+                                          decl: &'tcx hir::FnDecl,
                                           cfg: &cfg::CFG,
-                                          body: &hir::Expr,
+                                          body: &'tcx hir::Expr,
                                           sp: Span,
                                           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);
+    let id_range = intravisit::compute_id_range_for_fn_body(fk, decl, body, sp, id, &tcx.map);
     let (all_loans, move_data) =
         gather_loans::gather_loans_in_fn(this, id, decl, body);
 
@@ -241,7 +247,7 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
 /// the `BorrowckCtxt` itself , e.g. the flowgraph visualizer.
 pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    fn_parts: FnParts<'a>,
+    fn_parts: FnParts<'tcx>,
     cfg: &cfg::CFG)
     -> (BorrowckCtxt<'a, 'tcx>, AnalysisData<'a, 'tcx>)
 {
@@ -257,11 +263,13 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
         }
     };
 
+    let body = tcx.map.expr(fn_parts.body);
+
     let dataflow_data = build_borrowck_dataflow_data(&mut bccx,
                                                      fn_parts.kind,
                                                      &fn_parts.decl,
                                                      cfg,
-                                                     &fn_parts.body,
+                                                     body,
                                                      fn_parts.span,
                                                      fn_parts.id);
 
@@ -407,8 +415,8 @@ pub fn closure_to_block(closure_id: ast::NodeId,
                         tcx: TyCtxt) -> ast::NodeId {
     match tcx.map.get(closure_id) {
         hir_map::NodeExpr(expr) => match expr.node {
-            hir::ExprClosure(.., ref block, _) => {
-                block.id
+            hir::ExprClosure(.., body_id, _) => {
+                body_id.node_id()
             }
             _ => {
                 bug!("encountered non-closure id: {}", closure_id)
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index b67c2c8ec9c..786b59e818d 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -29,7 +29,7 @@ use rustc::ty::{self, TyCtxt};
 use rustc_errors::DiagnosticBuilder;
 
 use rustc::hir::def::*;
-use rustc::hir::intravisit::{self, Visitor, FnKind};
+use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
 use rustc::hir::print::pat_to_string;
 use rustc::hir::{self, Pat, PatKind};
 
@@ -41,12 +41,16 @@ use syntax_pos::Span;
 
 struct OuterVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
 
-impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> {
-    fn visit_expr(&mut self, _expr: &hir::Expr) {
+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: &hir::TraitItem) {
+    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 {
@@ -54,7 +58,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> {
         }
     }
 
-    fn visit_impl_item(&mut self, item: &hir::ImplItem) {
+    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 {
@@ -62,8 +66,8 @@ impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> {
         }
     }
 
-    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
-                b: &'v hir::Expr, s: Span, id: ast::NodeId) {
+    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")
         }
@@ -90,8 +94,12 @@ struct MatchVisitor<'a, 'tcx: 'a> {
     param_env: &'a ty::ParameterEnvironment<'tcx>
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for MatchVisitor<'a, 'tcx> {
-    fn visit_expr(&mut self, ex: &hir::Expr) {
+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)
+    }
+
+    fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
         intravisit::walk_expr(self, ex);
 
         match ex.node {
@@ -102,7 +110,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MatchVisitor<'a, 'tcx> {
         }
     }
 
-    fn visit_local(&mut self, loc: &hir::Local) {
+    fn visit_local(&mut self, loc: &'tcx hir::Local) {
         intravisit::walk_local(self, loc);
 
         self.check_irrefutable(&loc.pat, false);
@@ -111,8 +119,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MatchVisitor<'a, 'tcx> {
         self.check_patterns(false, slice::ref_slice(&loc.pat));
     }
 
-    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl,
-                b: &'v hir::Expr, s: Span, n: ast::NodeId) {
+    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);
 
         for input in &fd.inputs {
@@ -557,6 +565,10 @@ struct AtBindingPatternVisitor<'a, 'b:'a, 'tcx:'b> {
 }
 
 impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
+        NestedVisitorMap::None
+    }
+
     fn visit_pat(&mut self, pat: &Pat) {
         match pat.node {
             PatKind::Binding(.., ref subpat) => {
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 053d3072ddf..9fcab123989 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -33,7 +33,6 @@ use graphviz::IntoCow;
 use syntax::ast;
 use rustc::hir::{Expr, PatKind};
 use rustc::hir;
-use rustc::hir::intravisit::FnKind;
 use syntax::ptr::P;
 use syntax::codemap;
 use syntax::attr::IntType;
@@ -103,14 +102,16 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 _ => None
             },
             Some(ast_map::NodeTraitItem(ti)) => match ti.node {
-                hir::ConstTraitItem(..) => {
+                hir::ConstTraitItem(ref ty, ref expr_option) => {
                     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);
-                        resolve_trait_associated_const(tcx, ti, trait_id, substs)
+                        let default_value = expr_option.as_ref()
+                            .map(|expr| (&**expr, 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
                         // expression that generates the obligation, we could
@@ -141,33 +142,31 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
         let mut used_substs = false;
         let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
-            Some((&InlinedItem::Item(_, ref item), _)) => match item.node {
-                hir::ItemConst(ref ty, ref const_expr) => {
-                    Some((&**const_expr, tcx.ast_ty_to_prim_ty(ty)))
-                },
-                _ => None
-            },
-            Some((&InlinedItem::TraitItem(trait_id, ref ti), _)) => match ti.node {
-                hir::ConstTraitItem(..) => {
+            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) {
+            Some(Def::AssociatedConst(_)) => {
+                let trait_id = tcx.sess.cstore.trait_of_item(def_id);
+                // As mentioned in the comments above for in-crate
+                // constants, we only try to find the expression for a
+                // 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 {
-                        // As mentioned in the comments above for in-crate
-                        // constants, we only try to find the expression for
-                        // a trait-associated const if the caller gives us
-                        // the substitutions for the reference to it.
-                        resolve_trait_associated_const(tcx, ti, trait_id, substs)
+                        resolve_trait_associated_const(tcx, def_id, expr_ty, trait_id, substs)
                     } else {
                         None
                     }
+                } else {
+                    expr_ty
                 }
-                _ => None
-            },
-            Some((&InlinedItem::ImplItem(_, ref ii), _)) => match ii.node {
-                hir::ImplItemKind::Const(ref ty, ref expr) => {
-                    Some((&**expr, tcx.ast_ty_to_prim_ty(ty)))
-                },
-                _ => None
             },
+            Some(Def::Const(..)) => expr_ty,
             _ => None
         };
         // If we used the substitutions, particularly to choose an impl
@@ -196,24 +195,29 @@ fn inline_const_fn_from_external_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         return None;
     }
 
-    let fn_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
-        Some((&InlinedItem::Item(_, ref item), _)) => Some(item.id),
-        Some((&InlinedItem::ImplItem(_, ref item), _)) => Some(item.id),
-        _ => 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<FnLikeNode<'tcx>>
+                                       -> Option<ConstFnNode<'tcx>>
 {
     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) {
-            fn_id
+            if let ast_map::NodeInlinedItem(ii) = tcx.map.get(fn_id) {
+                return Some(ConstFnNode::Inlined(ii));
+            } else {
+                bug!("Got const fn from external crate, but it's not inlined")
+            }
         } else {
             return None;
         }
@@ -224,18 +228,10 @@ pub fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI
         None => return None
     };
 
-    match fn_like.kind() {
-        FnKind::ItemFn(_, _, _, hir::Constness::Const, ..) => {
-            Some(fn_like)
-        }
-        FnKind::Method(_, m, ..) => {
-            if m.constness == hir::Constness::Const {
-                Some(fn_like)
-            } else {
-                None
-            }
-        }
-        _ => None
+    if fn_like.constness() == hir::Constness::Const {
+        Some(ConstFnNode::Local(fn_like))
+    } else {
+        None
     }
 }
 
@@ -868,15 +864,22 @@ 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 (decl, result) = if let Some(fn_like) = lookup_const_fn_by_id(tcx, did) {
-              (fn_like.decl(), fn_like.body())
-          } else {
-              signal!(e, NonConstPath)
+          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()),
+              None => signal!(e, NonConstPath),
           };
-          assert_eq!(decl.inputs.len(), args.len());
+          let result = tcx.map.expr(body_id);
+          assert_eq!(arg_defs.len(), args.len());
 
           let mut call_args = DefIdMap();
-          for (arg, arg_expr) in decl.inputs.iter().zip(args.iter()) {
+          for (arg, arg_expr) in arg_defs.into_iter().zip(args.iter()) {
               let arg_hint = ty_hint.erase_hint();
               let arg_val = eval_const_expr_partial(
                   tcx,
@@ -885,7 +888,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                   fn_args
               )?;
               debug!("const call arg: {:?}", arg);
-              if let PatKind::Binding(_, def_id, _, _) = arg.pat.node {
+              if let Some(def_id) = arg {
                 assert!(call_args.insert(def_id, arg_val).is_none());
               }
           }
@@ -1068,11 +1071,13 @@ fn infer<'a, 'tcx>(i: ConstInt,
     }
 }
 
-fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                                ti: &'tcx hir::TraitItem,
-                                                trait_id: DefId,
-                                                rcvr_substs: &'tcx Substs<'tcx>)
-                                                -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)>
+fn resolve_trait_associated_const<'a, 'tcx: 'a>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    trait_item_id: DefId,
+    default_value: Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)>,
+    trait_id: DefId,
+    rcvr_substs: &'tcx Substs<'tcx>
+) -> Option<(&'tcx Expr, Option<ty::Ty<'tcx>>)>
 {
     let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs));
     debug!("resolve_trait_associated_const: trait_ref={:?}",
@@ -1103,21 +1108,16 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // when constructing the inference context above.
         match selection {
             traits::VtableImpl(ref impl_data) => {
+                let name = tcx.associated_item(trait_item_id).name;
                 let ac = tcx.associated_items(impl_data.impl_def_id)
-                    .find(|item| item.kind == ty::AssociatedKind::Const && item.name == ti.name);
+                    .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
                 match ac {
                     Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
-                    None => match ti.node {
-                        hir::ConstTraitItem(ref ty, Some(ref expr)) => {
-                            Some((&*expr, tcx.ast_ty_to_prim_ty(ty)))
-                        },
-                        _ => None,
-                    },
+                    None => default_value,
                 }
             }
             _ => {
-            span_bug!(ti.span,
-                      "resolve_trait_associated_const: unexpected vtable type")
+                bug!("resolve_trait_associated_const: unexpected vtable type")
             }
         }
     })
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 4759394aff1..f8507776651 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -696,13 +696,16 @@ impl fold::Folder for ReplaceBodyWithLoop {
 
 fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
                                        tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                       code: blocks::Code,
+                                       code: blocks::Code<'tcx>,
                                        mode: PpFlowGraphMode,
                                        mut out: W)
                                        -> io::Result<()> {
     let cfg = match code {
         blocks::Code::Expr(expr) => cfg::CFG::new(tcx, expr),
-        blocks::Code::FnLike(fn_like) => cfg::CFG::new(tcx, fn_like.body()),
+        blocks::Code::FnLike(fn_like) => {
+            let body = tcx.map.expr(fn_like.body());
+            cfg::CFG::new(tcx, body)
+        },
     };
     let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
     let lcfg = LabelledCFG {
diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs
index 250ef061e51..4595a940f10 100644
--- a/src/librustc_incremental/calculate_svh/mod.rs
+++ b/src/librustc_incremental/calculate_svh/mod.rs
@@ -34,7 +34,7 @@ use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
 use rustc::hir::intravisit as visit;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fx::FxHashMap;
 use rustc::util::common::record_time;
@@ -149,19 +149,30 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
     {
         assert!(def_id.is_local());
         debug!("HashItemsVisitor::calculate(def_id={:?})", def_id);
+        self.calculate_def_hash(DepNode::Hir(def_id), false, &mut walk_op);
+        self.calculate_def_hash(DepNode::HirBody(def_id), true, &mut walk_op);
+    }
+
+    fn calculate_def_hash<W>(&mut self,
+                             dep_node: DepNode<DefId>,
+                             hash_bodies: bool,
+                             walk_op: &mut W)
+        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
+    {
         let mut state = IchHasher::new();
         walk_op(&mut StrictVersionHashVisitor::new(&mut state,
                                                    self.tcx,
                                                    &mut self.def_path_hashes,
                                                    &mut self.codemap,
-                                                   self.hash_spans));
+                                                   self.hash_spans,
+                                                   hash_bodies));
         let bytes_hashed = state.bytes_hashed();
         let item_hash = state.finish();
-        self.hashes.insert(DepNode::Hir(def_id), item_hash);
-        debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, item_hash);
+        debug!("calculate_def_hash: dep_node={:?} hash={:?}", dep_node, item_hash);
+        self.hashes.insert(dep_node, item_hash);
 
         let bytes_hashed = self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() +
-                           bytes_hashed;
+            bytes_hashed;
         self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
     }
 
@@ -200,7 +211,8 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
                                                             self.tcx,
                                                             &mut self.def_path_hashes,
                                                             &mut self.codemap,
-                                                            self.hash_spans);
+                                                            self.hash_spans,
+                                                            false);
             visitor.hash_attributes(&krate.attrs);
         }
 
@@ -212,6 +224,10 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
 
 
 impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::None
+    }
+
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         self.calculate_node_id(item.id, |v| v.visit_item(item));
         visit::walk_item(self, item);
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index e2b141f2ea6..681ad2efa0c 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -52,6 +52,7 @@ pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> {
     hash_spans: bool,
     codemap: &'a mut CachingCodemapView<'tcx>,
     overflow_checks_enabled: bool,
+    hash_bodies: bool,
 }
 
 impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
@@ -59,7 +60,8 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
                tcx: TyCtxt<'hash, 'tcx, 'tcx>,
                def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>,
                codemap: &'a mut CachingCodemapView<'tcx>,
-               hash_spans: bool)
+               hash_spans: bool,
+               hash_bodies: bool)
                -> Self {
         let check_overflow = tcx.sess.opts.debugging_opts.force_overflow_checks
             .unwrap_or(tcx.sess.opts.debug_assertions);
@@ -71,6 +73,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
             hash_spans: hash_spans,
             codemap: codemap,
             overflow_checks_enabled: check_overflow,
+            hash_bodies: hash_bodies,
         }
     }
 
@@ -459,15 +462,16 @@ fn saw_ty(node: &Ty_) -> SawTyComponent {
 #[derive(Hash)]
 enum SawTraitOrImplItemComponent {
     SawTraitOrImplItemConst,
-    SawTraitOrImplItemMethod(Unsafety, Constness, Abi),
+    // The boolean signifies whether a body is present
+    SawTraitOrImplItemMethod(Unsafety, Constness, Abi, bool),
     SawTraitOrImplItemType
 }
 
 fn saw_trait_item(ti: &TraitItem_) -> SawTraitOrImplItemComponent {
     match *ti {
         ConstTraitItem(..) => SawTraitOrImplItemConst,
-        MethodTraitItem(ref sig, _) =>
-            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi),
+        MethodTraitItem(ref sig, ref body) =>
+            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, body.is_some()),
         TypeTraitItem(..) => SawTraitOrImplItemType
     }
 }
@@ -476,7 +480,7 @@ fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent {
     match *ii {
         ImplItemKind::Const(..) => SawTraitOrImplItemConst,
         ImplItemKind::Method(ref sig, _) =>
-            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi),
+            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true),
         ImplItemKind::Type(..) => SawTraitOrImplItemType
     }
 }
@@ -509,6 +513,14 @@ macro_rules! hash_span {
 }
 
 impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> visit::NestedVisitorMap<'this, 'tcx> {
+        if self.hash_bodies {
+            visit::NestedVisitorMap::OnlyBodies(&self.tcx.map)
+        } else {
+            visit::NestedVisitorMap::None
+        }
+    }
+
     fn visit_variant_data(&mut self,
                           s: &'tcx VariantData,
                           name: Name,
@@ -609,7 +621,8 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has
 
     fn visit_mod(&mut self, m: &'tcx Mod, _s: Span, n: NodeId) {
         debug!("visit_mod: st={:?}", self.st);
-        SawMod.hash(self.st); visit::walk_mod(self, m, n)
+        SawMod.hash(self.st);
+        visit::walk_mod(self, m, n)
     }
 
     fn visit_ty(&mut self, t: &'tcx Ty) {
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index 85c35bf79ce..40873011a7b 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -114,7 +114,8 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
 
         match dep_node {
             DepNode::Krate |
-            DepNode::Hir(_) => {
+            DepNode::Hir(_) |
+            DepNode::HirBody(_) => {
                 // HIR nodes are inputs, so if we are asserting that the HIR node is
                 // dirty, we check the dirty input set.
                 if !self.dirty_inputs.contains(&dep_node) {
@@ -143,7 +144,8 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
 
         match dep_node {
             DepNode::Krate |
-            DepNode::Hir(_) => {
+            DepNode::Hir(_) |
+            DepNode::HirBody(_) => {
                 // For HIR nodes, check the inputs.
                 if self.dirty_inputs.contains(&dep_node) {
                     let dep_node_str = self.dep_node_str(&dep_node);
diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs
index 73311ee96c5..562efa4b0d2 100644
--- a/src/librustc_incremental/persist/hash.rs
+++ b/src/librustc_incremental/persist/hash.rs
@@ -45,7 +45,9 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> {
     pub fn is_hashable(dep_node: &DepNode<DefId>) -> bool {
         match *dep_node {
             DepNode::Krate |
-            DepNode::Hir(_) => true,
+            DepNode::Hir(_) |
+            DepNode::HirBody(_) =>
+                true,
             DepNode::MetaData(def_id) => !def_id.is_local(),
             _ => false,
         }
@@ -58,7 +60,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> {
             }
 
             // HIR nodes (which always come from our crate) are an input:
-            DepNode::Hir(def_id) => {
+            DepNode::Hir(def_id) | DepNode::HirBody(def_id) => {
                 assert!(def_id.is_local(),
                         "cannot hash HIR for non-local def-id {:?} => {:?}",
                         def_id,
diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs
index 289eebb2162..05e21aa19b1 100644
--- a/src/librustc_incremental/persist/save.rs
+++ b/src/librustc_incremental/persist/save.rs
@@ -145,8 +145,8 @@ pub fn encode_dep_graph(preds: &Predecessors,
     for (&target, sources) in &preds.inputs {
         match *target {
             DepNode::MetaData(ref def_id) => {
-                // Metadata *targets* are always local metadata nodes. We handle
-                // those in `encode_metadata_hashes`, which comes later.
+                // Metadata *targets* are always local metadata nodes. We have
+                // already handled those in `encode_metadata_hashes`.
                 assert!(def_id.is_local());
                 continue;
             }
diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs
index 806d20c72dc..6598b7dcc52 100644
--- a/src/librustc_metadata/astencode.rs
+++ b/src/librustc_metadata/astencode.rs
@@ -10,7 +10,7 @@
 
 use rustc::hir::map as ast_map;
 
-use rustc::hir::intravisit::{Visitor, IdRangeComputingVisitor, IdRange};
+use rustc::hir::intravisit::{Visitor, IdRangeComputingVisitor, IdRange, NestedVisitorMap};
 
 use cstore::CrateMetadata;
 use encoder::EncodeContext;
@@ -43,13 +43,9 @@ enum TableEntry<'tcx> {
 }
 
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
-    pub fn encode_inlined_item(&mut self, ii: InlinedItemRef) -> Lazy<Ast<'tcx>> {
-        let mut id_visitor = IdRangeComputingVisitor::new();
-        match ii {
-            InlinedItemRef::Item(_, i) => id_visitor.visit_item(i),
-            InlinedItemRef::TraitItem(_, ti) => id_visitor.visit_trait_item(ti),
-            InlinedItemRef::ImplItem(_, ii) => id_visitor.visit_impl_item(ii),
-        }
+    pub fn encode_inlined_item(&mut self, ii: InlinedItemRef<'tcx>) -> Lazy<Ast<'tcx>> {
+        let mut id_visitor = IdRangeComputingVisitor::new(&self.tcx.map);
+        ii.visit(&mut id_visitor);
 
         let ii_pos = self.position();
         ii.encode(self).unwrap();
@@ -60,11 +56,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 ecx: self,
                 count: 0,
             };
-            match ii {
-                InlinedItemRef::Item(_, i) => visitor.visit_item(i),
-                InlinedItemRef::TraitItem(_, ti) => visitor.visit_trait_item(ti),
-                InlinedItemRef::ImplItem(_, ii) => visitor.visit_impl_item(ii),
-            }
+            ii.visit(&mut visitor);
             visitor.count
         };
 
@@ -81,7 +73,11 @@ struct SideTableEncodingIdVisitor<'a, 'b: 'a, 'tcx: 'b> {
     count: usize,
 }
 
-impl<'a, 'b, 'tcx, 'v> Visitor<'v> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> {
+impl<'a, 'b, 'tcx> Visitor<'tcx> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.ecx.tcx.map)
+    }
+
     fn visit_id(&mut self, id: ast::NodeId) {
         debug!("Encoding side tables for id {}", id);
 
@@ -122,17 +118,13 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata,
                      }];
 
     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,
                                        parent_def_path,
                                        parent_did,
                                        ii,
-                                       tcx.sess.next_node_id());
+                                       item_node_id);
 
-    let item_node_id = match ii {
-        &InlinedItem::Item(_, ref i) => i.id,
-        &InlinedItem::TraitItem(_, ref ti) => ti.id,
-        &InlinedItem::ImplItem(_, ref ii) => ii.id,
-    };
     let inlined_did = tcx.map.local_def_id(item_node_id);
     let ty = tcx.item_type(orig_did);
     let generics = tcx.item_generics(orig_did);
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 4b90d925972..573b2f6d2a6 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -443,12 +443,10 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
 
         let find_inlined_item_root = |inlined_item_id| {
             let mut node = inlined_item_id;
-            let mut path = Vec::with_capacity(10);
 
             // 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 {
-                path.push(node);
                 let parent_node = tcx.map.get_parent_node(node);
                 if parent_node == node {
                     return node;
@@ -464,27 +462,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
                     .borrow_mut()
                     .insert(def_id, None);
             }
-            Some(&InlinedItem::Item(d, ref item)) => {
-                assert_eq!(d, def_id);
-                let inlined_root_node_id = find_inlined_item_root(item.id);
-                cache_inlined_item(def_id, item.id, inlined_root_node_id);
-            }
-            Some(&InlinedItem::TraitItem(_, ref trait_item)) => {
-                let inlined_root_node_id = find_inlined_item_root(trait_item.id);
-                cache_inlined_item(def_id, trait_item.id, inlined_root_node_id);
-
-                // Associated consts already have to be evaluated in `typeck`, so
-                // the logic to do that already exists in `middle`. In order to
-                // reuse that code, it needs to be able to look up the traits for
-                // inlined items.
-                let ty_trait_item = tcx.associated_item(def_id).clone();
-                let trait_item_def_id = tcx.map.local_def_id(trait_item.id);
-                tcx.associated_items.borrow_mut()
-                   .insert(trait_item_def_id, ty_trait_item);
-            }
-            Some(&InlinedItem::ImplItem(_, ref impl_item)) => {
-                let inlined_root_node_id = find_inlined_item_root(impl_item.id);
-                cache_inlined_item(def_id, impl_item.id, inlined_root_node_id);
+            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);
             }
         }
 
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index a243962b4ee..4839c409335 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -39,7 +39,7 @@ use syntax_pos;
 
 use rustc::hir::{self, PatKind};
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
-use rustc::hir::intravisit::Visitor;
+use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
 use rustc::hir::intravisit;
 
 use super::index_builder::{FromId, IndexBuilder, Untracked};
@@ -516,9 +516,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             generics: Some(self.encode_generics(def_id)),
             predicates: Some(self.encode_predicates(def_id)),
 
-            ast: if trait_item.kind == ty::AssociatedKind::Const {
+            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::TraitItem(trait_def_id, ast_item)))
+                Some(self.encode_inlined_item(
+                    InlinedItemRef::from_trait_item(trait_def_id, ast_item, tcx)
+                ))
             } else {
                 None
             },
@@ -527,6 +531,8 @@ 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);
@@ -587,7 +593,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             predicates: Some(self.encode_predicates(def_id)),
 
             ast: if ast {
-                Some(self.encode_inlined_item(InlinedItemRef::ImplItem(impl_def_id, ast_item)))
+                Some(self.encode_inlined_item(
+                    InlinedItemRef::from_impl_item(impl_def_id, ast_item, tcx)
+                ))
             } else {
                 None
             },
@@ -630,7 +638,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.tcx.lookup_deprecation(def_id).map(|depr| self.lazy(&depr))
     }
 
-    fn encode_info_for_item(&mut self, (def_id, item): (DefId, &hir::Item)) -> Entry<'tcx> {
+    fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> Entry<'tcx> {
         let tcx = self.tcx;
 
         debug!("encoding info for item at {}",
@@ -817,7 +825,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             ast: match item.node {
                 hir::ItemConst(..) |
                 hir::ItemFn(_, _, hir::Constness::Const, ..) => {
-                    Some(self.encode_inlined_item(InlinedItemRef::Item(def_id, item)))
+                    Some(self.encode_inlined_item(
+                        InlinedItemRef::from_item(def_id, item, tcx)
+                    ))
                 }
                 _ => None,
             },
@@ -973,6 +983,9 @@ struct EncodeVisitor<'a, 'b: 'a, 'tcx: 'b> {
 }
 
 impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.index.tcx.map)
+    }
     fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
         intravisit::walk_expr(self, ex);
         self.index.encode_info_for_expr(ex);
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index a148ae08c53..94bf8936fe6 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -736,7 +736,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(.., ref body, _) => body.id,
+                        hir::ExprClosure(.., body_id, _) => body_id.node_id(),
                         _ => {
                             span_bug!(expr.span, "closure expr is not a closure expr");
                         }
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index cfeac606f03..32639cc3f86 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -23,7 +23,6 @@ use rustc_const_eval as const_eval;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc::dep_graph::DepNode;
 use rustc::hir::def_id::DefId;
-use rustc::hir::intravisit::FnKind;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::infer::InferCtxt;
 use rustc::ty::subst::Subst;
@@ -51,11 +50,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
             MirSource::Static(..) => hir::Constness::Const,
             MirSource::Fn(id) => {
                 let fn_like = FnLikeNode::from_node(infcx.tcx.map.get(id));
-                match fn_like.map(|f| f.kind()) {
-                    Some(FnKind::ItemFn(_, _, _, c, ..)) => c,
-                    Some(FnKind::Method(_, m, ..)) => m.constness,
-                    _ => hir::Constness::NotConst
-                }
+                fn_like.map_or(hir::Constness::NotConst, |f| f.constness())
             }
             MirSource::Promoted(..) => bug!()
         };
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index 992c0e9b5fc..88d02d7d004 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -30,7 +30,7 @@ use rustc::traits::Reveal;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::Substs;
 use rustc::hir;
-use rustc::hir::intravisit::{self, FnKind, Visitor};
+use rustc::hir::intravisit::{self, FnKind, Visitor, NestedVisitorMap};
 use syntax::abi::Abi;
 use syntax::ast;
 use syntax_pos::Span;
@@ -144,6 +144,10 @@ impl<'a, 'gcx> BuildMir<'a, 'gcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+    }
+
     // Const and static items.
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         match item.node {
@@ -210,7 +214,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
     fn visit_fn(&mut self,
                 fk: FnKind<'tcx>,
                 decl: &'tcx hir::FnDecl,
-                body: &'tcx hir::Expr,
+                body_id: hir::ExprId,
                 span: Span,
                 id: ast::NodeId) {
         // fetch the fully liberated fn signature (that is, all bound
@@ -223,7 +227,7 @@ 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), 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)
@@ -237,12 +241,14 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
                     (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)
         });
 
-        intravisit::walk_fn(self, fk, decl, body, span, id);
+        intravisit::walk_fn(self, fk, decl, body_id, span, id);
     }
 }
 
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 4ff2beb3fdb..57929879f94 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -19,7 +19,6 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 use rustc::hir;
 use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
-use rustc::hir::intravisit::FnKind;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::traits::{self, Reveal};
 use rustc::ty::{self, TyCtxt, Ty};
@@ -116,15 +115,10 @@ impl fmt::Display for Mode {
 
 pub fn is_const_fn(tcx: TyCtxt, def_id: DefId) -> bool {
     if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
-        let fn_like = FnLikeNode::from_node(tcx.map.get(node_id));
-        match fn_like.map(|f| f.kind()) {
-            Some(FnKind::ItemFn(_, _, _, c, ..)) => {
-                c == hir::Constness::Const
-            }
-            Some(FnKind::Method(_, m, ..)) => {
-                m.constness == hir::Constness::Const
-            }
-            _ => false
+        if let Some(fn_like) = FnLikeNode::from_node(tcx.map.get(node_id)) {
+            fn_like.constness() == hir::Constness::Const
+        } else {
+            false
         }
     } else {
         tcx.sess.cstore.is_const_fn(def_id)
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index d9b1f247c72..86f56d00358 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -27,7 +27,7 @@
 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::{eval_const_expr_partial, lookup_const_by_id};
+use rustc_const_eval::{ConstFnNode, eval_const_expr_partial, lookup_const_by_id};
 use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math};
 use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
 use rustc_const_eval::ErrKind::UnresolvedPath;
@@ -48,7 +48,7 @@ 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};
+use rustc::hir::intravisit::{self, FnKind, Visitor, NestedVisitorMap};
 
 use std::collections::hash_map::Entry;
 use std::cmp::Ordering;
@@ -100,7 +100,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
             .enter(|infcx| f(&mut euv::ExprUseVisitor::new(self, &infcx)))
     }
 
-    fn global_expr(&mut self, mode: Mode, expr: &hir::Expr) -> ConstQualif {
+    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(),
@@ -132,9 +132,9 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
     }
 
     fn fn_like(&mut self,
-               fk: FnKind,
-               fd: &hir::FnDecl,
-               b: &hir::Expr,
+               fk: FnKind<'gcx>,
+               fd: &'gcx hir::FnDecl,
+               b: hir::ExprId,
                s: Span,
                fn_id: ast::NodeId)
                -> ConstQualif {
@@ -160,7 +160,8 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
         };
 
         let qualif = self.with_mode(mode, |this| {
-            this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b));
+            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
         });
@@ -179,21 +180,39 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
 
     /// 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 {
-        if let Some(fn_like) = lookup_const_fn_by_id(self.tcx, def_id) {
-            let qualif = self.fn_like(fn_like.kind(),
-                                      fn_like.decl(),
-                                      fn_like.body(),
-                                      fn_like.span(),
-                                      fn_like.id());
-            self.add_qualif(qualif);
+        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());
 
-            if ret_ty.type_contents(self.tcx).interior_unsafe() {
-                self.add_qualif(ConstQualif::MUTABLE_MEM);
-            }
+                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")
+                };
 
-            true
-        } else {
-            false
+                self.add_qualif(qualif);
+
+                if ret_ty.type_contents(self.tcx).interior_unsafe() {
+                    self.add_qualif(ConstQualif::MUTABLE_MEM);
+                }
+
+                true
+            },
+            None => false
         }
     }
 
@@ -213,8 +232,12 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
-    fn visit_item(&mut self, i: &hir::Item) {
+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)
+    }
+
+    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 {
@@ -240,7 +263,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
         }
     }
 
-    fn visit_trait_item(&mut self, t: &'v hir::TraitItem) {
+    fn visit_trait_item(&mut self, t: &'tcx hir::TraitItem) {
         match t.node {
             hir::ConstTraitItem(_, ref default) => {
                 if let Some(ref expr) = *default {
@@ -253,7 +276,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
         }
     }
 
-    fn visit_impl_item(&mut self, i: &'v hir::ImplItem) {
+    fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) {
         match i.node {
             hir::ImplItemKind::Const(_, ref expr) => {
                 self.global_expr(Mode::Const, &expr);
@@ -263,15 +286,15 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
     }
 
     fn visit_fn(&mut self,
-                fk: FnKind<'v>,
-                fd: &'v hir::FnDecl,
-                b: &'v hir::Expr,
+                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);
     }
 
-    fn visit_pat(&mut self, p: &hir::Pat) {
+    fn visit_pat(&mut self, p: &'tcx hir::Pat) {
         match p.node {
             PatKind::Lit(ref lit) => {
                 self.global_expr(Mode::Const, &lit);
@@ -296,7 +319,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
         }
     }
 
-    fn visit_block(&mut self, block: &hir::Block) {
+    fn visit_block(&mut self, block: &'tcx hir::Block) {
         // Check all statements in the block
         for stmt in &block.stmts {
             match stmt.node {
@@ -315,7 +338,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
         intravisit::walk_block(self, block);
     }
 
-    fn visit_expr(&mut self, ex: &hir::Expr) {
+    fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
         let mut outer = self.qualif;
         self.qualif = ConstQualif::empty();
 
diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs
index ba236ea93a4..b7858013988 100644
--- a/src/librustc_passes/hir_stats.rs
+++ b/src/librustc_passes/hir_stats.rs
@@ -106,7 +106,7 @@ impl<'k> StatCollector<'k> {
 }
 
 impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
-    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'v>> {
+    fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'v> {
         panic!("visit_nested_xxx must be manually implemented in this visitor")
     }
 
@@ -172,7 +172,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: &'v hir::Expr,
+                b: hir::ExprId,
                 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 a622a3faf70..10f464a9901 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -13,7 +13,7 @@ use rustc::session::Session;
 
 use rustc::dep_graph::DepNode;
 use rustc::hir::map::Map;
-use rustc::hir::intravisit::{self, Visitor};
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir;
 use syntax::ast;
 use syntax_pos::Span;
@@ -59,16 +59,20 @@ pub fn check_crate(sess: &Session, map: &Map) {
     }.as_deep_visitor());
 }
 
-impl<'a, 'ast, 'v> Visitor<'v> for CheckLoopVisitor<'a, 'ast> {
-    fn visit_item(&mut self, i: &hir::Item) {
+impl<'a, 'ast> Visitor<'ast> for CheckLoopVisitor<'a, 'ast> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'ast> {
+        NestedVisitorMap::OnlyBodies(&self.hir_map)
+    }
+
+    fn visit_item(&mut self, i: &'ast hir::Item) {
         self.with_context(Normal, |v| intravisit::walk_item(v, i));
     }
 
-    fn visit_impl_item(&mut self, i: &hir::ImplItem) {
+    fn visit_impl_item(&mut self, i: &'ast hir::ImplItem) {
         self.with_context(Normal, |v| intravisit::walk_impl_item(v, i));
     }
 
-    fn visit_expr(&mut self, e: &hir::Expr) {
+    fn visit_expr(&mut self, e: &'ast hir::Expr) {
         match e.node {
             hir::ExprWhile(ref e, ref b, _) => {
                 self.with_context(Loop(LoopKind::WhileLoop), |v| {
@@ -79,8 +83,8 @@ impl<'a, 'ast, 'v> Visitor<'v> for CheckLoopVisitor<'a, 'ast> {
             hir::ExprLoop(ref b, _, source) => {
                 self.with_context(Loop(LoopKind::Loop(source)), |v| v.visit_block(&b));
             }
-            hir::ExprClosure(.., ref b, _) => {
-                self.with_context(Closure, |v| v.visit_expr(&b));
+            hir::ExprClosure(.., b, _) => {
+                self.with_context(Closure, |v| v.visit_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 7386be2528c..ddb5af1e80c 100644
--- a/src/librustc_passes/rvalues.rs
+++ b/src/librustc_passes/rvalues.rs
@@ -18,7 +18,7 @@ use rustc::ty::{self, TyCtxt, ParameterEnvironment};
 use rustc::traits::Reveal;
 
 use rustc::hir;
-use rustc::hir::intravisit::{self, Visitor};
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use syntax::ast;
 use syntax_pos::Span;
 
@@ -31,11 +31,15 @@ struct RvalueContext<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for RvalueContext<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+    }
+
     fn visit_fn(&mut self,
-                fk: intravisit::FnKind<'v>,
-                fd: &'v hir::FnDecl,
-                b: &'v hir::Expr,
+                fk: intravisit::FnKind<'tcx>,
+                fd: &'tcx hir::FnDecl,
+                b: hir::ExprId,
                 s: Span,
                 fn_id: ast::NodeId) {
         // FIXME (@jroesch) change this to be an inference context
@@ -46,8 +50,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for RvalueContext<'a, 'tcx> {
                 tcx: infcx.tcx,
                 param_env: &param_env
             };
+            let body = infcx.tcx.map.expr(b);
             let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
-            euv.walk_fn(fd, b);
+            euv.walk_fn(fd, 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 b5daf0284e1..ffb5045fe3b 100644
--- a/src/librustc_passes/static_recursion.rs
+++ b/src/librustc_passes/static_recursion.rs
@@ -20,7 +20,7 @@ use rustc::util::nodemap::NodeMap;
 use syntax::ast;
 use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax_pos::Span;
-use rustc::hir::intravisit::{self, Visitor};
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir;
 
 use std::cell::RefCell;
@@ -36,6 +36,10 @@ struct CheckCrateVisitor<'a, 'ast: 'a> {
 }
 
 impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'ast> {
+        NestedVisitorMap::None
+    }
+
     fn visit_item(&mut self, it: &'ast hir::Item) {
         match it.node {
             hir::ItemStatic(..) |
@@ -200,6 +204,10 @@ impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
 }
 
 impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'ast> {
+        NestedVisitorMap::OnlyBodies(&self.ast_map)
+    }
+
     fn visit_item(&mut self, it: &'ast hir::Item) {
         self.with_item_id_pushed(it.id, |v| intravisit::walk_item(v, it), it.span);
     }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index ee18968ff35..8b8172bf5b5 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -30,7 +30,7 @@ use rustc::dep_graph::DepNode;
 use rustc::hir::{self, PatKind};
 use rustc::hir::def::{self, Def, CtorKind};
 use rustc::hir::def_id::DefId;
-use rustc::hir::intravisit::{self, Visitor};
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::itemlikevisit::DeepVisitor;
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
 use rustc::lint;
@@ -120,8 +120,8 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
     /// We want to visit items in the context of their containing
     /// module and so forth, so supply a crate for doing a deep walk.
-    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
-        Some(&self.tcx.map)
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::All(&self.tcx.map)
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item) {
@@ -432,8 +432,8 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for PrivacyVisitor<'a, 'tcx> {
     /// We want to visit items in the context of their containing
     /// module and so forth, so supply a crate for doing a deep walk.
-    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
-        Some(&self.tcx.map)
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::All(&self.tcx.map)
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item) {
@@ -615,6 +615,10 @@ impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
+        NestedVisitorMap::None
+    }
+
     fn visit_ty(&mut self, ty: &hir::Ty) {
         if let hir::TyPath(hir::QPath::Resolved(_, ref path)) = ty.node {
             if self.inner.path_is_private_type(path) {
@@ -640,8 +644,8 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a
 impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
     /// We want to visit items in the context of their containing
     /// module and so forth, so supply a crate for doing a deep walk.
-    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
-        Some(&self.tcx.map)
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::All(&self.tcx.map)
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item) {
@@ -1059,8 +1063,12 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
-    fn visit_item(&mut self, item: &hir::Item) {
+impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+    }
+
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
         let tcx = self.tcx;
         let min = |vis1: ty::Visibility, vis2| {
             if vis1.is_at_least(vis2, &tcx.map) { vis2 } else { vis1 }
@@ -1163,11 +1171,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tc
         }
     }
 
-    fn visit_impl_item(&mut self, _impl_item: &'v hir::ImplItem) {
+    fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) {
         // handled in `visit_item` above
     }
 
-    fn visit_ty(&mut self, ty: &hir::Ty) {
+    fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
         if let hir::TyImplTrait(..) = ty.node {
             // Check the traits being exposed, as they're separate,
             // e.g. `impl Iterator<Item=T>` has two predicates,
@@ -1181,9 +1189,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tc
     }
 
     // Don't recurse into expressions in array sizes or const initializers
-    fn visit_expr(&mut self, _: &hir::Expr) {}
+    fn visit_expr(&mut self, _: &'tcx hir::Expr) {}
     // Don't recurse into patterns in function arguments
-    fn visit_pat(&mut self, _: &hir::Pat) {}
+    fn visit_pat(&mut self, _: &'tcx hir::Pat) {}
 }
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs
index aa23a181722..9ed5a5d148c 100644
--- a/src/librustc_trans/symbol_names_test.rs
+++ b/src/librustc_trans/symbol_names_test.rs
@@ -15,7 +15,7 @@
 //! paths etc in all kinds of annoying scenarios.
 
 use rustc::hir;
-use rustc::hir::intravisit::{self, Visitor};
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use syntax::ast;
 
 use common::SharedCrateContext;
@@ -67,6 +67,10 @@ impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for SymbolNamesTest<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::None
+    }
+
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         self.process_attrs(item.id);
         intravisit::walk_item(self, item);
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 75287d4064a..0854ca3d1bb 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -23,7 +23,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               expr: &hir::Expr,
                               _capture: hir::CaptureClause,
                               decl: &'gcx hir::FnDecl,
-                              body: &'gcx hir::Expr,
+                              body_id: hir::ExprId,
                               expected: Expectation<'tcx>)
                               -> Ty<'tcx> {
         debug!("check_expr_closure(expr={:?},expected={:?})",
@@ -37,6 +37,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);
         self.check_closure(expr, expected_kind, decl, body, expected_sig)
     }
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 2babb81bc40..0c4e5e4fa0d 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -119,7 +119,7 @@ use syntax::symbol::{Symbol, InternedString, keywords};
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::{self, BytePos, Span};
 
-use rustc::hir::intravisit::{self, Visitor};
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
 use rustc::hir::{self, PatKind};
 use rustc::hir::print as pprust;
@@ -538,6 +538,10 @@ struct CheckItemTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
 struct CheckItemBodiesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
 
 impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.ccx.tcx.map)
+    }
+
     fn visit_item(&mut self, i: &'tcx hir::Item) {
         check_item_type(self.ccx, i);
         intravisit::walk_item(self, i);
@@ -630,9 +634,11 @@ pub fn check_drop_impls(ccx: &CrateCtxt) -> CompileResult {
 
 fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                            decl: &'tcx hir::FnDecl,
-                           body: &'tcx hir::Expr,
+                           body_id: hir::ExprId,
                            fn_id: ast::NodeId,
                            span: Span) {
+    let body = ccx.tcx.map.expr(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,
@@ -643,13 +649,13 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     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);
+        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, &fn_sig);
+            inh.normalize_associated_types_in(body.span, body_id.node_id(), &fn_sig);
 
         let fcx = check_fn(&inh, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body);
 
@@ -659,7 +665,7 @@ 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);
+        fcx.regionck_fn(fn_id, decl, body_id);
         fcx.resolve_type_vars_in_fn(decl, body, fn_id);
     });
 }
@@ -694,6 +700,10 @@ impl<'a, 'gcx, 'tcx> GatherLocalsVisitor<'a, 'gcx, 'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
+        NestedVisitorMap::None
+    }
+
     // Add explicitly-declared locals.
     fn visit_local(&mut self, local: &'gcx hir::Local) {
         let o_ty = match local.ty {
@@ -750,7 +760,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
 
     // Don't descend into the bodies of nested closures
     fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
-                _: &'gcx hir::Expr, _: Span, _: ast::NodeId) { }
+                _: hir::ExprId, _: Span, _: ast::NodeId) { }
 }
 
 /// Helper used by check_bare_fn and check_expr_fn. Does the grungy work of checking a function
@@ -911,8 +921,8 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
            ccx.tcx.item_path_str(ccx.tcx.map.local_def_id(it.id)));
     let _indenter = indenter();
     match it.node {
-      hir::ItemFn(ref decl, .., ref body) => {
-        check_bare_fn(ccx, &decl, &body, it.id, it.span);
+      hir::ItemFn(ref decl, .., body_id) => {
+        check_bare_fn(ccx, &decl, body_id, it.id, it.span);
       }
       hir::ItemImpl(.., ref impl_item_refs) => {
         debug!("ItemImpl {} with id {}", it.name, it.id);
@@ -923,8 +933,8 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
                 hir::ImplItemKind::Const(_, ref expr) => {
                     check_const(ccx, &expr, impl_item.id)
                 }
-                hir::ImplItemKind::Method(ref sig, ref body) => {
-                    check_bare_fn(ccx, &sig.decl, body, impl_item.id, impl_item.span);
+                hir::ImplItemKind::Method(ref sig, body_id) => {
+                    check_bare_fn(ccx, &sig.decl, body_id, impl_item.id, impl_item.span);
                 }
                 hir::ImplItemKind::Type(_) => {
                     // Nothing to do here.
@@ -938,8 +948,8 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
                 hir::ConstTraitItem(_, Some(ref expr)) => {
                     check_const(ccx, &expr, trait_item.id)
                 }
-                hir::MethodTraitItem(ref sig, Some(ref body)) => {
-                    check_bare_fn(ccx, &sig.decl, body, trait_item.id, trait_item.span);
+                hir::MethodTraitItem(ref sig, Some(body_id)) => {
+                    check_bare_fn(ccx, &sig.decl, body_id, trait_item.id, trait_item.span);
                 }
                 hir::MethodTraitItem(_, None) |
                 hir::ConstTraitItem(_, None) |
@@ -1102,14 +1112,14 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                          err.emit()
                     }
                 }
-                hir::ImplItemKind::Method(_, ref body) => {
+                hir::ImplItemKind::Method(_, body_id) => {
                     let trait_span = tcx.map.span_if_local(ty_trait_item.def_id);
                     if ty_trait_item.kind == ty::AssociatedKind::Method {
                         let err_count = tcx.sess.err_count();
                         compare_impl_method(ccx,
                                             &ty_impl_item,
                                             impl_item.span,
-                                            body.id,
+                                            body_id.node_id(),
                                             &ty_trait_item,
                                             impl_trait_ref,
                                             trait_span,
@@ -1119,7 +1129,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,
+                                                body_id.node_id(),
                                                 &ty_trait_item,
                                                 impl_trait_ref,
                                                 trait_span,
@@ -3791,8 +3801,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           hir::ExprMatch(ref discrim, ref arms, match_src) => {
             self.check_match(expr, &discrim, arms, expected, match_src)
           }
-          hir::ExprClosure(capture, ref decl, ref body, _) => {
-              self.check_expr_closure(expr, capture, &decl, &body, expected)
+          hir::ExprClosure(capture, ref decl, body_id, _) => {
+              self.check_expr_closure(expr, capture, &decl, body_id, expected)
           }
           hir::ExprBlock(ref b) => {
             self.check_block_with_expected(&b, expected)
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index ca33682480c..3cc99b6e4e5 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -99,7 +99,7 @@ use std::mem;
 use std::ops::Deref;
 use syntax::ast;
 use syntax_pos::Span;
-use rustc::hir::intravisit::{self, Visitor};
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::{self, PatKind};
 
 use self::SubjectNode::Subject;
@@ -113,7 +113,7 @@ macro_rules! ignore_err {
 // PUBLIC ENTRY POINTS
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    pub fn regionck_expr(&self, e: &hir::Expr) {
+    pub fn regionck_expr(&self, e: &'gcx hir::Expr) {
         let mut rcx = RegionCtxt::new(self, RepeatingScope(e.id), e.id, Subject(e.id));
         if self.err_count_since_creation() == 0 {
             // regionck assumes typeck succeeded
@@ -141,13 +141,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn regionck_fn(&self,
                        fn_id: ast::NodeId,
                        decl: &hir::FnDecl,
-                       body: &hir::Expr) {
+                       body_id: hir::ExprId) {
         debug!("regionck_fn(id={})", fn_id);
-        let mut rcx = RegionCtxt::new(self, RepeatingScope(body.id), body.id, Subject(fn_id));
+        let node_id = body_id.node_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, self.tcx.map.span(fn_id));
+            rcx.visit_fn_body(fn_id, decl, body_id, self.tcx.map.span(fn_id));
         }
 
         rcx.free_region_map.relate_free_regions_from_predicates(
@@ -267,14 +268,14 @@ 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: &hir::Expr,
+                     body_id: hir::ExprId,
                      span: Span)
     {
         // When we enter a function, we can derive
         debug!("visit_fn_body(id={})", id);
 
         let call_site = self.tcx.region_maps.lookup_code_extent(
-            region::CodeExtentData::CallSiteScope { fn_id: id, body_id: body.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 = {
@@ -300,19 +301,20 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                          .chain(Some(fn_sig.output))
                          .collect();
 
-        let old_body_id = self.set_body_id(body.id);
-        self.relate_free_regions(&fn_sig_tys[..], body.id, span);
-        self.link_fn_args(self.tcx.region_maps.node_extent(body.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()),
                           &fn_decl.inputs[..]);
+        let body = self.tcx.map.expr(body_id);
         self.visit_expr(body);
-        self.visit_region_obligations(body.id);
+        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);
         let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope));
         self.type_of_node_must_outlive(infer::CallReturn(span),
-                                       body.id,
+                                       body_id.node_id(),
                                        call_site_region);
 
         self.region_bound_pairs.truncate(old_region_bounds_pairs_len);
@@ -469,7 +471,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
     // (..) FIXME(#3238) should use visit_pat, not visit_arm/visit_local,
     // However, right now we run into an issue whereby some free
     // regions are not properly related if they appear within the
@@ -478,14 +480,18 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> {
     // hierarchy, and in particular the relationships between free
     // regions, until regionck, as described in #3238.
 
-    fn visit_fn(&mut self, _fk: intravisit::FnKind<'v>, fd: &'v hir::FnDecl,
-                b: &'v hir::Expr, span: Span, id: ast::NodeId) {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
+        NestedVisitorMap::OnlyBodies(&self.tcx.map)
+    }
+
+    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)
     }
 
     //visit_pat: visit_pat, // (..) see above
 
-    fn visit_arm(&mut self, arm: &hir::Arm) {
+    fn visit_arm(&mut self, arm: &'gcx hir::Arm) {
         // see above
         for p in &arm.pats {
             self.constrain_bindings_in_pat(p);
@@ -493,14 +499,14 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> {
         intravisit::walk_arm(self, arm);
     }
 
-    fn visit_local(&mut self, l: &hir::Local) {
+    fn visit_local(&mut self, l: &'gcx hir::Local) {
         // see above
         self.constrain_bindings_in_pat(&l.pat);
         self.link_local(l);
         intravisit::walk_local(self, l);
     }
 
-    fn visit_expr(&mut self, expr: &hir::Expr) {
+    fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
         debug!("regionck::visit_expr(e={:?}, repeating_scope={})",
                expr, self.repeating_scope);
 
@@ -737,8 +743,8 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> {
                 intravisit::walk_expr(self, expr);
             }
 
-            hir::ExprClosure(.., ref body, _) => {
-                self.check_expr_fn_block(expr, &body);
+            hir::ExprClosure(.., body_id, _) => {
+                self.check_expr_fn_block(expr, body_id);
             }
 
             hir::ExprLoop(ref body, _, _) => {
@@ -823,9 +829,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn check_expr_fn_block(&mut self,
-                           expr: &hir::Expr,
-                           body: &hir::Expr) {
-        let repeating_scope = self.set_repeating_scope(body.id);
+                           expr: &'gcx hir::Expr,
+                           body_id: hir::ExprId) {
+        let repeating_scope = self.set_repeating_scope(body_id.node_id());
         intravisit::walk_expr(self, expr);
         self.set_repeating_scope(repeating_scope);
     }
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index 1ea47107c3b..63d20416bde 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -50,14 +50,14 @@ use rustc::infer::UpvarRegion;
 use syntax::ast;
 use syntax_pos::Span;
 use rustc::hir;
-use rustc::hir::intravisit::{self, Visitor};
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::util::nodemap::NodeMap;
 
 ///////////////////////////////////////////////////////////////////////////
 // PUBLIC ENTRY POINTS
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    pub fn closure_analyze(&self, body: &hir::Expr) {
+    pub fn closure_analyze(&self, body: &'gcx hir::Expr) {
         let mut seed = SeedBorrowKind::new(self);
         seed.visit_expr(body);
 
@@ -77,11 +77,15 @@ struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     temp_closure_kinds: NodeMap<ty::ClosureKind>,
 }
 
-impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for SeedBorrowKind<'a, 'gcx, 'tcx> {
-    fn visit_expr(&mut self, expr: &hir::Expr) {
+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)
+    }
+
+    fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
         match expr.node {
-            hir::ExprClosure(cc, _, ref body, _) => {
-                self.check_closure(expr, cc, &body);
+            hir::ExprClosure(cc, _, body_id, _) => {
+                self.check_closure(expr, cc, body_id);
             }
 
             _ => { }
@@ -99,7 +103,7 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> {
     fn check_closure(&mut self,
                      expr: &hir::Expr,
                      capture_clause: hir::CaptureClause,
-                     _body: &hir::Expr)
+                     _body_id: hir::ExprId)
     {
         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) {
@@ -153,14 +157,15 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
                        id: ast::NodeId,
                        span: Span,
                        decl: &hir::FnDecl,
-                       body: &hir::Expr) {
+                       body_id: hir::ExprId) {
         /*!
          * 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,
@@ -484,11 +489,15 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
     }
 }
 
-impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for 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)
+    }
+
     fn visit_fn(&mut self,
-                fn_kind: intravisit::FnKind<'v>,
-                decl: &'v hir::FnDecl,
-                body: &'v hir::Expr,
+                fn_kind: intravisit::FnKind<'gcx>,
+                decl: &'gcx hir::FnDecl,
+                body: hir::ExprId,
                 span: Span,
                 id: ast::NodeId)
     {
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 1ad81660f83..b6d0ff03a07 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -23,7 +23,7 @@ use syntax::ast;
 use syntax_pos::Span;
 use errors::DiagnosticBuilder;
 
-use rustc::hir::intravisit::{self, Visitor};
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir;
 
 pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> {
@@ -127,8 +127,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                     }
                 }
             }
-            hir::ItemFn(.., ref body) => {
-                self.check_item_fn(item, body);
+            hir::ItemFn(.., body_id) => {
+                self.check_item_fn(item, body_id);
             }
             hir::ItemStatic(..) => {
                 self.check_item_type(item);
@@ -347,7 +347,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
 
     fn check_item_fn(&mut self,
                      item: &hir::Item,
-                     body: &hir::Expr)
+                     body_id: hir::ExprId)
     {
         self.for_item(item).with_fcx(|fcx, this| {
             let free_substs = &fcx.parameter_environment.free_substs;
@@ -364,7 +364,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);
+            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
@@ -609,6 +609,10 @@ fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, def_id: DefId) {
 }
 
 impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
+        NestedVisitorMap::None
+    }
+
     fn visit_item(&mut self, i: &hir::Item) {
         debug!("visit_item: {:?}", i);
         self.check_item_well_formed(i);
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 45b3dae3e9f..84b0303e5cf 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -27,14 +27,14 @@ use syntax::ast;
 use syntax_pos::{DUMMY_SP, Span};
 
 use rustc::hir::print::pat_to_string;
-use rustc::hir::intravisit::{self, Visitor};
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::{self, PatKind};
 
 ///////////////////////////////////////////////////////////////////////////
 // Entry point functions
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    pub fn resolve_type_vars_in_expr(&self, e: &hir::Expr, item_id: ast::NodeId) {
+    pub fn resolve_type_vars_in_expr(&self, e: &'gcx hir::Expr, item_id: ast::NodeId) {
         assert_eq!(self.writeback_errors.get(), false);
         let mut wbcx = WritebackCx::new(self);
         wbcx.visit_expr(e);
@@ -47,8 +47,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn resolve_type_vars_in_fn(&self,
-                                   decl: &hir::FnDecl,
-                                   body: &hir::Expr,
+                                   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);
@@ -186,8 +186,12 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
 // below. In general, a function is made into a `visitor` if it must
 // traffic in node-ids or update tables in the type context etc.
 
-impl<'cx, 'gcx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'gcx, 'tcx> {
-    fn visit_stmt(&mut self, s: &hir::Stmt) {
+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)
+    }
+
+    fn visit_stmt(&mut self, s: &'gcx hir::Stmt) {
         if self.fcx.writeback_errors.get() {
             return;
         }
@@ -196,7 +200,7 @@ impl<'cx, 'gcx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'gcx, 'tcx> {
         intravisit::walk_stmt(self, s);
     }
 
-    fn visit_expr(&mut self, e: &hir::Expr) {
+    fn visit_expr(&mut self, e: &'gcx hir::Expr) {
         if self.fcx.writeback_errors.get() {
             return;
         }
@@ -216,7 +220,7 @@ impl<'cx, 'gcx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'gcx, 'tcx> {
         intravisit::walk_expr(self, e);
     }
 
-    fn visit_block(&mut self, b: &hir::Block) {
+    fn visit_block(&mut self, b: &'gcx hir::Block) {
         if self.fcx.writeback_errors.get() {
             return;
         }
@@ -225,7 +229,7 @@ impl<'cx, 'gcx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'gcx, 'tcx> {
         intravisit::walk_block(self, b);
     }
 
-    fn visit_pat(&mut self, p: &hir::Pat) {
+    fn visit_pat(&mut self, p: &'gcx hir::Pat) {
         if self.fcx.writeback_errors.get() {
             return;
         }
@@ -240,7 +244,7 @@ impl<'cx, 'gcx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'gcx, 'tcx> {
         intravisit::walk_pat(self, p);
     }
 
-    fn visit_local(&mut self, l: &hir::Local) {
+    fn visit_local(&mut self, l: &'gcx hir::Local) {
         if self.fcx.writeback_errors.get() {
             return;
         }
@@ -251,7 +255,7 @@ impl<'cx, 'gcx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'gcx, 'tcx> {
         intravisit::walk_local(self, l);
     }
 
-    fn visit_ty(&mut self, t: &hir::Ty) {
+    fn visit_ty(&mut self, t: &'gcx hir::Ty) {
         match t.node {
             hir::TyArray(ref ty, ref count_expr) => {
                 self.visit_ty(&ty);
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index a507077bef7..abbf5601484 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -385,7 +385,6 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
         self.check_item(item);
     }
 
-
     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 0dcc0bcc316..011c8262518 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -83,7 +83,7 @@ use syntax::symbol::{Symbol, keywords};
 use syntax_pos::Span;
 
 use rustc::hir::{self, map as hir_map, print as pprust};
-use rustc::hir::intravisit::{self, Visitor};
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
 
@@ -128,13 +128,66 @@ struct CollectItemTypesVisitor<'a, 'tcx: 'a> {
     ccx: &'a CrateCtxt<'a, 'tcx>
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> {
-    fn visit_item(&mut self, item: &hir::Item) {
-        convert_item(self.ccx, item);
+impl<'a, 'tcx> CollectItemTypesVisitor<'a, 'tcx> {
+    /// Collect item types is structured into two tasks. The outer
+    /// task, `CollectItem`, walks the entire content of an item-like
+    /// thing, including its body. It also spawns an inner task,
+    /// `CollectItemSig`, which walks only the signature. This inner
+    /// task is the one that writes the item-type into the various
+    /// maps.  This setup ensures that the item body is never
+    /// accessible to the task that computes its signature, so that
+    /// changes to the body don't affect the signature.
+    ///
+    /// Consider an example function `foo` that also has a closure in its body:
+    ///
+    /// ```
+    /// fn foo(<sig>) {
+    ///     ...
+    ///     let bar = || ...; // we'll label this closure as "bar" below
+    /// }
+    /// ```
+    ///
+    /// This results in a dep-graph like so. I've labeled the edges to
+    /// document where they arise.
+    ///
+    /// ```
+    /// [HirBody(foo)] -2--> [CollectItem(foo)] -4-> [ItemSignature(bar)]
+    ///                       ^           ^
+    ///                       1           3
+    /// [Hir(foo)] -----------+-6-> [CollectItemSig(foo)] -5-> [ItemSignature(foo)]
+    /// ```
+    ///
+    /// 1. This is added by the `visit_all_item_likes_in_krate`.
+    /// 2. This is added when we fetch the item body.
+    /// 3. This is added because `CollectItem` launches `CollectItemSig`.
+    ///    - it is arguably false; if we refactor the `with_task` system;
+    ///      we could get probably rid of it, but it is also harmless enough.
+    /// 4. This is added by the code in `visit_expr` when we write to `item_types`.
+    /// 5. This is added by the code in `convert_item` when we write to `item_types`;
+    ///    note that this write occurs inside the `CollectItemSig` task.
+    /// 6. Added by explicit `read` below
+    fn with_collect_item_sig<OP>(&self, id: ast::NodeId, op: OP)
+        where OP: FnOnce()
+    {
+        let def_id = self.ccx.tcx.map.local_def_id(id);
+        self.ccx.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), || {
+            self.ccx.tcx.map.read(id);
+            op();
+        });
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.ccx.tcx.map)
+    }
+
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
+        self.with_collect_item_sig(item.id, || convert_item(self.ccx, item));
         intravisit::walk_item(self, item);
     }
 
-    fn visit_expr(&mut self, expr: &hir::Expr) {
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
         if let hir::ExprClosure(..) = expr.node {
             let def_id = self.ccx.tcx.map.local_def_id(expr.id);
             generics_of_def_id(self.ccx, def_id);
@@ -143,7 +196,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> {
         intravisit::walk_expr(self, expr);
     }
 
-    fn visit_ty(&mut self, ty: &hir::Ty) {
+    fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
         if let hir::TyImplTrait(..) = ty.node {
             let def_id = self.ccx.tcx.map.local_def_id(ty.id);
             generics_of_def_id(self.ccx, def_id);
@@ -151,8 +204,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> {
         intravisit::walk_ty(self, ty);
     }
 
-    fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
-        convert_impl_item(self.ccx, impl_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)
+        });
         intravisit::walk_impl_item(self, impl_item);
     }
 }
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 9f29319430d..009330065f3 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -489,8 +489,8 @@ impl<'a, 'hir> HirCollector<'a, 'hir> {
 }
 
 impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> {
-    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'hir>> {
-        Some(self.map)
+    fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'hir> {
+        intravisit::NestedVisitorMap::All(&self.map)
     }
 
     fn visit_item(&mut self, item: &'hir hir::Item) {
diff --git a/src/test/incremental/change_private_impl_method_cc/struct_point.rs b/src/test/incremental/change_private_impl_method_cc/struct_point.rs
index bb7f7025c59..4d9ca77969b 100644
--- a/src/test/incremental/change_private_impl_method_cc/struct_point.rs
+++ b/src/test/incremental/change_private_impl_method_cc/struct_point.rs
@@ -23,9 +23,8 @@
 #![rustc_partition_reused(module="struct_point-fn_write_field", cfg="rpass2")]
 #![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")]
 
-// FIXME(#37720) these two should be reused, but data gets entangled across crates
-#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")]
-#![rustc_partition_translated(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")]
+#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="rpass2")]
+#![rustc_partition_reused(module="struct_point-fn_calls_methods_in_another_impl", cfg="rpass2")]
 
 extern crate point;
 
@@ -33,8 +32,7 @@ extern crate point;
 mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    // FIXME(#37720) data gets entangled across crates
-    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -45,8 +43,7 @@ mod fn_calls_methods_in_same_impl {
 mod fn_calls_methods_in_another_impl {
     use point::Point;
 
-    // FIXME(#37720) data gets entangled across crates
-    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
     pub fn dirty() {
         let mut x = Point { x: 2.0, y: 2.0 };
         x.translate(3.0, 3.0);
diff --git a/src/test/incremental/change_pub_inherent_method_body/struct_point.rs b/src/test/incremental/change_pub_inherent_method_body/struct_point.rs
index 665eafb4f4e..e0047e5ec64 100644
--- a/src/test/incremental/change_pub_inherent_method_body/struct_point.rs
+++ b/src/test/incremental/change_pub_inherent_method_body/struct_point.rs
@@ -19,9 +19,7 @@
 
 #![rustc_partition_translated(module="struct_point-point", cfg="rpass2")]
 
-// FIXME(#35078) -- this gets recompiled because we don't separate sig from body
-#![rustc_partition_translated(module="struct_point-fn_calls_changed_method", cfg="rpass2")]
-
+#![rustc_partition_reused(module="struct_point-fn_calls_changed_method", cfg="rpass2")]
 #![rustc_partition_reused(module="struct_point-fn_calls_another_method", cfg="rpass2")]
 #![rustc_partition_reused(module="struct_point-fn_make_struct", cfg="rpass2")]
 #![rustc_partition_reused(module="struct_point-fn_read_field", cfg="rpass2")]
@@ -52,8 +50,7 @@ mod point {
 mod fn_calls_changed_method {
     use point::Point;
 
-    // FIXME(#35078) -- this gets recompiled because we don't separate sig from body
-    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
     pub fn check() {
         let p = Point { x: 2.0, y: 2.0 };
         p.distance_from_origin();
diff --git a/src/test/incremental/hashes/call_expressions.rs b/src/test/incremental/hashes/call_expressions.rs
index d2030d93554..647ff5dedf3 100644
--- a/src/test/incremental/hashes/call_expressions.rs
+++ b/src/test/incremental/hashes/call_expressions.rs
@@ -36,9 +36,11 @@ pub fn change_callee_function() {
 }
 
 #[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")]
 pub fn change_callee_function() {
     callee2(1, 2)
@@ -53,9 +55,11 @@ pub fn change_argument_function() {
 }
 
 #[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")]
 pub fn change_argument_function() {
     callee1(1, 3)
@@ -70,9 +74,11 @@ mod change_callee_indirectly_function {
     #[cfg(not(cfail1))]
     use super::callee2 as callee;
 
-    #[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")]
     pub fn change_callee_indirectly_function() {
         callee(1, 2)
@@ -94,9 +100,11 @@ pub fn change_callee_method() {
 }
 
 #[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")]
 pub fn change_callee_method() {
     let s = Struct;
@@ -113,9 +121,11 @@ pub fn change_argument_method() {
 }
 
 #[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")]
 pub fn change_argument_method() {
     let s = Struct;
@@ -132,9 +142,11 @@ pub fn change_ufcs_callee_method() {
 }
 
 #[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")]
 pub fn change_ufcs_callee_method() {
     let s = Struct;
@@ -151,9 +163,11 @@ pub fn change_argument_method_ufcs() {
 }
 
 #[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")]
 pub fn change_argument_method_ufcs() {
     let s = Struct;
@@ -170,9 +184,11 @@ pub fn change_to_ufcs() {
 }
 
 #[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")]
 pub fn change_to_ufcs() {
     let s = Struct;
@@ -192,9 +208,11 @@ mod change_ufcs_callee_indirectly {
     #[cfg(not(cfail1))]
     use super::Struct2 as Struct;
 
-    #[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")]
     pub fn change_ufcs_callee_indirectly() {
         let s = Struct;
diff --git a/src/test/incremental/hashes/for_loops.rs b/src/test/incremental/hashes/for_loops.rs
index 7a8502f7caa..bae3c9bf596 100644
--- a/src/test/incremental/hashes/for_loops.rs
+++ b/src/test/incremental/hashes/for_loops.rs
@@ -36,9 +36,11 @@ fn change_loop_body() {
 }
 
 #[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")]
 fn change_loop_body() {
     let mut _x = 0;
@@ -61,9 +63,11 @@ fn change_iteration_variable_name() {
 }
 
 #[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")]
 fn change_iteration_variable_name() {
     let mut _x = 0;
@@ -86,9 +90,11 @@ fn change_iteration_variable_pattern() {
 }
 
 #[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")]
 fn change_iteration_variable_pattern() {
     let mut _x = 0;
@@ -111,9 +117,11 @@ fn change_iterable() {
 }
 
 #[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")]
 fn change_iterable() {
     let mut _x = 0;
@@ -135,9 +143,11 @@ fn add_break() {
 }
 
 #[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")]
 fn add_break() {
     let mut _x = 0;
@@ -160,9 +170,11 @@ fn add_loop_label() {
 }
 
 #[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")]
 fn add_loop_label() {
     let mut _x = 0;
@@ -185,9 +197,11 @@ fn add_loop_label_to_break() {
 }
 
 #[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")]
 fn add_loop_label_to_break() {
     let mut _x = 0;
@@ -212,9 +226,11 @@ fn change_break_label() {
 }
 
 #[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")]
 fn change_break_label() {
     let mut _x = 0;
@@ -239,9 +255,11 @@ fn add_loop_label_to_continue() {
 }
 
 #[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")]
 fn add_loop_label_to_continue() {
     let mut _x = 0;
@@ -266,9 +284,11 @@ fn change_continue_label() {
 }
 
 #[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")]
 fn change_continue_label() {
     let mut _x = 0;
@@ -293,9 +313,11 @@ fn change_continue_to_break() {
 }
 
 #[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")]
 fn change_continue_to_break() {
     let mut _x = 0;
diff --git a/src/test/incremental/hashes/if_expressions.rs b/src/test/incremental/hashes/if_expressions.rs
index ba6289f754e..c39eeab34c8 100644
--- a/src/test/incremental/hashes/if_expressions.rs
+++ b/src/test/incremental/hashes/if_expressions.rs
@@ -36,9 +36,11 @@ pub fn change_condition(x: bool) -> u32 {
 }
 
 #[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")]
 pub fn change_condition(x: bool) -> u32 {
     if !x {
@@ -59,9 +61,11 @@ pub fn change_then_branch(x: bool) -> u32 {
 }
 
 #[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")]
 pub fn change_then_branch(x: bool) -> u32 {
     if x {
@@ -84,9 +88,11 @@ pub fn change_else_branch(x: bool) -> u32 {
 }
 
 #[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")]
 pub fn change_else_branch(x: bool) -> u32 {
     if x {
@@ -111,9 +117,11 @@ pub fn add_else_branch(x: bool) -> u32 {
 }
 
 #[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")]
 pub fn add_else_branch(x: bool) -> u32 {
     let mut ret = 1;
@@ -139,9 +147,11 @@ pub fn change_condition_if_let(x: Option<u32>) -> u32 {
 }
 
 #[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")]
 pub fn change_condition_if_let(x: Option<u32>) -> u32 {
     if let Some(_) = x {
@@ -164,9 +174,11 @@ pub fn change_then_branch_if_let(x: Option<u32>) -> u32 {
 }
 
 #[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")]
 pub fn change_then_branch_if_let(x: Option<u32>) -> u32 {
     if let Some(x) = x {
@@ -189,9 +201,11 @@ pub fn change_else_branch_if_let(x: Option<u32>) -> u32 {
 }
 
 #[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")]
 pub fn change_else_branch_if_let(x: Option<u32>) -> u32 {
     if let Some(x) = x {
@@ -216,9 +230,11 @@ pub fn add_else_branch_if_let(x: Option<u32>) -> u32 {
 }
 
 #[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")]
 pub fn add_else_branch_if_let(x: Option<u32>) -> u32 {
     let mut ret = 1;
diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs
index 7bfd8077a3d..9e532548e11 100644
--- a/src/test/incremental/hashes/let_expressions.rs
+++ b/src/test/incremental/hashes/let_expressions.rs
@@ -32,9 +32,11 @@ pub fn change_name() {
 }
 
 #[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")]
 pub fn change_name() {
     let _y = 2u64;
@@ -49,9 +51,11 @@ pub fn add_type() {
 }
 
 #[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")]
 pub fn add_type() {
     let _x: u32 = 2u32;
@@ -66,9 +70,11 @@ pub fn change_type() {
 }
 
 #[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")]
 pub fn change_type() {
     let _x: u8 = 2;
@@ -83,9 +89,11 @@ pub fn change_mutability_of_reference_type() {
 }
 
 #[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")]
 pub fn change_mutability_of_reference_type() {
     let _x: &mut u64;
@@ -100,9 +108,11 @@ pub fn change_mutability_of_slot() {
 }
 
 #[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")]
 pub fn change_mutability_of_slot() {
     let _x: u64 = 0;
@@ -117,9 +127,11 @@ pub fn change_simple_binding_to_pattern() {
 }
 
 #[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")]
 pub fn change_simple_binding_to_pattern() {
     let (_a, _b) = (0u8, 'x');
@@ -134,9 +146,11 @@ pub fn change_name_in_pattern() {
 }
 
 #[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")]
 pub fn change_name_in_pattern() {
     let (_a, _c) = (1u8, 'y');
@@ -151,9 +165,11 @@ pub fn add_ref_in_pattern() {
 }
 
 #[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")]
 pub fn add_ref_in_pattern() {
     let (ref _a, _b) = (1u8, 'y');
@@ -168,9 +184,11 @@ pub fn add_amp_in_pattern() {
 }
 
 #[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")]
 pub fn add_amp_in_pattern() {
     let (&_a, _b) = (&1u8, 'y');
@@ -185,9 +203,11 @@ pub fn change_mutability_of_binding_in_pattern() {
 }
 
 #[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")]
 pub fn change_mutability_of_binding_in_pattern() {
     let (mut _a, _b) = (99u8, 'q');
@@ -202,9 +222,11 @@ pub fn add_initializer() {
 }
 
 #[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")]
 pub fn add_initializer() {
     let _x: i16 = 3i16;
@@ -219,9 +241,11 @@ pub fn change_initializer() {
 }
 
 #[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")]
 pub fn change_initializer() {
     let _x = 5u16;
diff --git a/src/test/incremental/hashes/loop_expressions.rs b/src/test/incremental/hashes/loop_expressions.rs
index eaa5f68b98c..da43ef3c461 100644
--- a/src/test/incremental/hashes/loop_expressions.rs
+++ b/src/test/incremental/hashes/loop_expressions.rs
@@ -36,9 +36,11 @@ fn change_loop_body() {
 }
 
 #[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")]
 fn change_loop_body() {
     let mut _x = 0;
@@ -60,9 +62,11 @@ fn add_break() {
 }
 
 #[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")]
 fn add_break() {
     let mut _x = 0;
@@ -85,9 +89,11 @@ fn add_loop_label() {
 }
 
 #[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")]
 fn add_loop_label() {
     let mut _x = 0;
@@ -110,9 +116,11 @@ fn add_loop_label_to_break() {
 }
 
 #[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")]
 fn add_loop_label_to_break() {
     let mut _x = 0;
@@ -137,9 +145,11 @@ fn change_break_label() {
 }
 
 #[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")]
 fn change_break_label() {
     let mut _x = 0;
@@ -164,9 +174,11 @@ fn add_loop_label_to_continue() {
 }
 
 #[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")]
 fn add_loop_label_to_continue() {
     let mut _x = 0;
@@ -191,9 +203,11 @@ fn change_continue_label() {
 }
 
 #[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")]
 fn change_continue_label() {
     let mut _x = 0;
@@ -218,9 +232,11 @@ fn change_continue_to_break() {
 }
 
 #[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")]
 fn change_continue_to_break() {
     let mut _x = 0;
diff --git a/src/test/incremental/hashes/match_expressions.rs b/src/test/incremental/hashes/match_expressions.rs
index 95e94a91c5b..48f99b834ce 100644
--- a/src/test/incremental/hashes/match_expressions.rs
+++ b/src/test/incremental/hashes/match_expressions.rs
@@ -36,9 +36,11 @@ pub fn add_arm(x: u32) -> u32 {
 }
 
 #[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")]
 pub fn add_arm(x: u32) -> u32 {
     match x {
@@ -62,9 +64,11 @@ pub fn change_order_of_arms(x: u32) -> u32 {
 }
 
 #[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")]
 pub fn change_order_of_arms(x: u32) -> u32 {
     match x {
@@ -87,9 +91,11 @@ pub fn add_guard_clause(x: u32, y: bool) -> u32 {
 }
 
 #[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")]
 pub fn add_guard_clause(x: u32, y: bool) -> u32 {
     match x {
@@ -112,9 +118,11 @@ pub fn change_guard_clause(x: u32, y: bool) -> u32 {
 }
 
 #[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")]
 pub fn change_guard_clause(x: u32, y: bool) -> u32 {
     match x {
@@ -137,9 +145,11 @@ pub fn add_at_binding(x: u32) -> u32 {
 }
 
 #[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")]
 pub fn add_at_binding(x: u32) -> u32 {
     match x {
@@ -162,9 +172,11 @@ pub fn change_name_of_at_binding(x: u32) -> u32 {
 }
 
 #[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")]
 pub fn change_name_of_at_binding(x: u32) -> u32 {
     match x {
@@ -186,9 +198,11 @@ pub fn change_simple_name_to_pattern(x: u32) -> u32 {
 }
 
 #[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")]
 pub fn change_simple_name_to_pattern(x: u32) -> u32 {
     match (x, x & 1) {
@@ -210,9 +224,11 @@ pub fn change_name_in_pattern(x: u32) -> u32 {
 }
 
 #[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")]
 pub fn change_name_in_pattern(x: u32) -> u32 {
     match (x, x & 1) {
@@ -234,9 +250,11 @@ pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 {
 }
 
 #[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")]
 pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 {
     match (x, x & 1) {
@@ -257,9 +275,11 @@ pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 {
 }
 
 #[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")]
 pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 {
     match (x, x & 1) {
@@ -280,9 +300,11 @@ pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 {
 }
 
 #[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")]
 pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 {
     match (&x, x & 1) {
@@ -304,9 +326,11 @@ pub fn change_rhs_of_arm(x: u32) -> u32 {
 }
 
 #[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")]
 pub fn change_rhs_of_arm(x: u32) -> u32 {
     match x {
@@ -329,9 +353,11 @@ pub fn add_alternative_to_arm(x: u32) -> u32 {
 }
 
 #[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")]
 pub fn add_alternative_to_arm(x: u32) -> u32 {
     match x {
diff --git a/src/test/incremental/hashes/panic_exprs.rs b/src/test/incremental/hashes/panic_exprs.rs
index f5f4c0042b4..5d4d434fd63 100644
--- a/src/test/incremental/hashes/panic_exprs.rs
+++ b/src/test/incremental/hashes/panic_exprs.rs
@@ -34,9 +34,11 @@ pub fn indexing(slice: &[u8]) -> u8 {
 }
 
 #[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")]
 pub fn indexing(slice: &[u8]) -> u8 {
     slice[100]
@@ -50,9 +52,11 @@ pub fn arithmetic_overflow_plus(val: i32) -> 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_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn arithmetic_overflow_plus(val: i32) -> i32 {
     val + 1
@@ -66,9 +70,11 @@ pub fn arithmetic_overflow_minus(val: i32) -> 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_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn arithmetic_overflow_minus(val: i32) -> i32 {
     val - 1
@@ -82,9 +88,11 @@ pub fn arithmetic_overflow_mult(val: i32) -> 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_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn arithmetic_overflow_mult(val: i32) -> i32 {
     val * 2
@@ -98,9 +106,11 @@ pub fn arithmetic_overflow_negation(val: i32) -> 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_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn arithmetic_overflow_negation(val: i32) -> i32 {
     -val
@@ -114,9 +124,11 @@ pub fn division_by_zero(val: i32) -> 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_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn division_by_zero(val: i32) -> i32 {
     2 / val
@@ -129,9 +141,11 @@ pub fn mod_by_zero(val: i32) -> 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_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn mod_by_zero(val: i32) -> i32 {
     2 % val
@@ -150,6 +164,8 @@ pub fn bitwise(val: i32) -> i32 {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn bitwise(val: i32) -> i32 {
@@ -166,6 +182,8 @@ pub fn logical(val1: bool, val2: bool, val3: bool) -> bool {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn logical(val1: bool, val2: bool, val3: bool) -> bool {
diff --git a/src/test/incremental/hashes/panic_exprs_no_overflow_checks.rs b/src/test/incremental/hashes/panic_exprs_no_overflow_checks.rs
index b84b7f5f378..b3fc8e2d36d 100644
--- a/src/test/incremental/hashes/panic_exprs_no_overflow_checks.rs
+++ b/src/test/incremental/hashes/panic_exprs_no_overflow_checks.rs
@@ -41,9 +41,11 @@ pub fn indexing(slice: &[u8]) -> u8 {
 }
 
 #[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")]
 pub fn indexing(slice: &[u8]) -> u8 {
     slice[100]
@@ -58,9 +60,11 @@ pub fn arithmetic_overflow_plus_inherit(val: i32) -> 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_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 #[rustc_inherit_overflow_checks]
 pub fn arithmetic_overflow_plus_inherit(val: i32) -> i32 {
@@ -76,9 +80,11 @@ pub fn arithmetic_overflow_minus_inherit(val: i32) -> 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_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 #[rustc_inherit_overflow_checks]
 pub fn arithmetic_overflow_minus_inherit(val: i32) -> i32 {
@@ -94,9 +100,11 @@ pub fn arithmetic_overflow_mult_inherit(val: i32) -> 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_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 #[rustc_inherit_overflow_checks]
 pub fn arithmetic_overflow_mult_inherit(val: i32) -> i32 {
@@ -112,9 +120,11 @@ pub fn arithmetic_overflow_negation_inherit(val: i32) -> 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_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 #[rustc_inherit_overflow_checks]
 pub fn arithmetic_overflow_negation_inherit(val: i32) -> i32 {
@@ -129,9 +139,11 @@ pub fn division_by_zero(val: i32) -> 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_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn division_by_zero(val: i32) -> i32 {
     2 / val
@@ -144,9 +156,11 @@ pub fn mod_by_zero(val: i32) -> 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_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn mod_by_zero(val: i32) -> i32 {
     2 % val
@@ -165,6 +179,8 @@ pub fn bitwise(val: i32) -> i32 {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn bitwise(val: i32) -> i32 {
@@ -181,6 +197,8 @@ pub fn logical(val1: bool, val2: bool, val3: bool) -> bool {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn logical(val1: bool, val2: bool, val3: bool) -> bool {
@@ -196,6 +214,8 @@ pub fn arithmetic_overflow_plus(val: i32) -> i32 {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn arithmetic_overflow_plus(val: i32) -> i32 {
@@ -212,6 +232,8 @@ pub fn arithmetic_overflow_minus(val: i32) -> i32 {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn arithmetic_overflow_minus(val: i32) -> i32 {
@@ -228,6 +250,8 @@ pub fn arithmetic_overflow_mult(val: i32) -> i32 {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn arithmetic_overflow_mult(val: i32) -> i32 {
@@ -244,6 +268,8 @@ pub fn arithmetic_overflow_negation(val: i32) -> i32 {
 #[cfg(not(cfail1))]
 #[rustc_clean(label="Hir", cfg="cfail2")]
 #[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn arithmetic_overflow_negation(val: i32) -> i32 {
diff --git a/src/test/incremental/hashes/struct_constructors.rs b/src/test/incremental/hashes/struct_constructors.rs
index c4366ea11e3..6a9f4698bf8 100644
--- a/src/test/incremental/hashes/struct_constructors.rs
+++ b/src/test/incremental/hashes/struct_constructors.rs
@@ -42,9 +42,11 @@ fn change_field_value_regular_struct() -> RegularStruct {
 }
 
 #[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")]
 fn change_field_value_regular_struct() -> RegularStruct {
     RegularStruct {
@@ -67,9 +69,11 @@ fn change_field_order_regular_struct() -> RegularStruct {
 }
 
 #[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")]
 fn change_field_order_regular_struct() -> RegularStruct {
     RegularStruct {
@@ -97,9 +101,11 @@ fn add_field_regular_struct() -> RegularStruct {
 }
 
 #[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")]
 fn add_field_regular_struct() -> RegularStruct {
     let struct1 = RegularStruct {
@@ -134,9 +140,11 @@ fn change_field_label_regular_struct() -> RegularStruct {
 }
 
 #[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")]
 fn change_field_label_regular_struct() -> RegularStruct {
     let struct1 = RegularStruct {
@@ -171,9 +179,11 @@ fn change_constructor_path_regular_struct() {
 }
 
 #[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")]
 fn change_constructor_path_regular_struct() {
     let _ = RegularStruct2 {
@@ -212,9 +222,11 @@ fn change_field_value_tuple_struct() -> TupleStruct {
 }
 
 #[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")]
 fn change_field_value_tuple_struct() -> TupleStruct {
     TupleStruct(0, 1, 3)
@@ -231,9 +243,11 @@ fn change_constructor_path_tuple_struct() {
 }
 
 #[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")]
 fn change_constructor_path_tuple_struct() {
     let _ = TupleStruct2(0, 1, 2);
diff --git a/src/test/incremental/hashes/unary_and_binary_exprs.rs b/src/test/incremental/hashes/unary_and_binary_exprs.rs
index 2c0ca004312..05b0dec4e7e 100644
--- a/src/test/incremental/hashes/unary_and_binary_exprs.rs
+++ b/src/test/incremental/hashes/unary_and_binary_exprs.rs
@@ -32,9 +32,11 @@ pub fn const_negation() -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn const_negation() -> i32 {
     -1
@@ -49,9 +51,11 @@ pub fn const_bitwise_not() -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn const_bitwise_not() -> i32 {
     !99
@@ -66,9 +70,11 @@ pub fn var_negation(x: i32, y: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn var_negation(x: i32, y: i32) -> i32 {
     -y
@@ -83,9 +89,11 @@ pub fn var_bitwise_not(x: i32, y: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn var_bitwise_not(x: i32, y: i32) -> i32 {
     !y
@@ -100,9 +108,11 @@ pub fn var_deref(x: &i32, y: &i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn var_deref(x: &i32, y: &i32) -> i32 {
     *y
@@ -117,9 +127,11 @@ pub fn first_const_add() -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn first_const_add() -> i32 {
     2 + 3
@@ -134,9 +146,11 @@ pub fn second_const_add() -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn second_const_add() -> i32 {
     1 + 3
@@ -151,9 +165,11 @@ pub fn first_var_add(a: i32, b: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn first_var_add(a: i32, b: i32) -> i32 {
     b + 2
@@ -168,9 +184,11 @@ pub fn second_var_add(a: i32, b: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn second_var_add(a: i32, b: i32) -> i32 {
     1 + b
@@ -185,9 +203,11 @@ pub fn plus_to_minus(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn plus_to_minus(a: i32) -> i32 {
     1 - a
@@ -202,9 +222,11 @@ pub fn plus_to_mult(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn plus_to_mult(a: i32) -> i32 {
     1 * a
@@ -219,9 +241,11 @@ pub fn plus_to_div(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn plus_to_div(a: i32) -> i32 {
     1 / a
@@ -236,9 +260,11 @@ pub fn plus_to_mod(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn plus_to_mod(a: i32) -> i32 {
     1 % a
@@ -253,9 +279,11 @@ pub fn and_to_or(a: bool, b: bool) -> bool {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn and_to_or(a: bool, b: bool) -> bool {
     a || b
@@ -270,9 +298,11 @@ pub fn bitwise_and_to_bitwise_or(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn bitwise_and_to_bitwise_or(a: i32) -> i32 {
     1 | a
@@ -287,9 +317,11 @@ pub fn bitwise_and_to_bitwise_xor(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn bitwise_and_to_bitwise_xor(a: i32) -> i32 {
     1 ^ a
@@ -304,9 +336,11 @@ pub fn bitwise_and_to_lshift(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn bitwise_and_to_lshift(a: i32) -> i32 {
     a << 1
@@ -321,9 +355,11 @@ pub fn bitwise_and_to_rshift(a: i32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn bitwise_and_to_rshift(a: i32) -> i32 {
     a >> 1
@@ -338,9 +374,11 @@ pub fn eq_to_uneq(a: i32) -> bool {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn eq_to_uneq(a: i32) -> bool {
     a != 1
@@ -355,9 +393,11 @@ pub fn eq_to_lt(a: i32) -> bool {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn eq_to_lt(a: i32) -> bool {
     a < 1
@@ -372,9 +412,11 @@ pub fn eq_to_gt(a: i32) -> bool {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn eq_to_gt(a: i32) -> bool {
     a > 1
@@ -389,9 +431,11 @@ pub fn eq_to_le(a: i32) -> bool {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn eq_to_le(a: i32) -> bool {
     a <= 1
@@ -406,9 +450,11 @@ pub fn eq_to_ge(a: i32) -> bool {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn eq_to_ge(a: i32) -> bool {
     a >= 1
@@ -425,9 +471,11 @@ pub fn type_cast(a: u8) -> u64 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn type_cast(a: u8) -> u64 {
     let b = a as u32;
@@ -444,9 +492,11 @@ pub fn value_cast(a: u32) -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn value_cast(a: u32) -> i32 {
     2 as i32
@@ -464,9 +514,11 @@ pub fn lvalue() -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn lvalue() -> i32 {
     let mut x = 10;
@@ -486,9 +538,11 @@ pub fn rvalue() -> i32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn rvalue() -> i32 {
     let mut x = 10;
@@ -505,9 +559,11 @@ pub fn index_to_slice(s: &[u8], i: usize, j: usize) -> u8 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfails2")]
-#[rustc_clean(label="Hir", cfg="cfails3")]
-#[rustc_metadata_dirty(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_clean(cfg="cfail2")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub fn index_to_slice(s: &[u8], i: usize, j: usize) -> u8 {
     s[j]
diff --git a/src/test/incremental/hashes/while_let_loops.rs b/src/test/incremental/hashes/while_let_loops.rs
index 405645bd1b8..f4fd7e709b4 100644
--- a/src/test/incremental/hashes/while_let_loops.rs
+++ b/src/test/incremental/hashes/while_let_loops.rs
@@ -36,9 +36,11 @@ fn change_loop_body() {
 }
 
 #[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")]
 fn change_loop_body() {
     let mut _x = 0;
@@ -61,9 +63,11 @@ fn change_loop_condition() {
 }
 
 #[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")]
 fn change_loop_condition() {
     let mut _x = 0;
@@ -85,9 +89,11 @@ fn add_break() {
 }
 
 #[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")]
 fn add_break() {
     let mut _x = 0;
@@ -110,9 +116,11 @@ fn add_loop_label() {
 }
 
 #[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")]
 fn add_loop_label() {
     let mut _x = 0;
@@ -135,9 +143,11 @@ fn add_loop_label_to_break() {
 }
 
 #[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")]
 fn add_loop_label_to_break() {
     let mut _x = 0;
@@ -162,9 +172,11 @@ fn change_break_label() {
 }
 
 #[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")]
 fn change_break_label() {
     let mut _x = 0;
@@ -189,9 +201,11 @@ fn add_loop_label_to_continue() {
 }
 
 #[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")]
 fn add_loop_label_to_continue() {
     let mut _x = 0;
@@ -216,9 +230,11 @@ fn change_continue_label() {
 }
 
 #[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")]
 fn change_continue_label() {
     let mut _x = 0;
@@ -243,9 +259,11 @@ fn change_continue_to_break() {
 }
 
 #[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")]
 fn change_continue_to_break() {
     let mut _x = 0;
diff --git a/src/test/incremental/hashes/while_loops.rs b/src/test/incremental/hashes/while_loops.rs
index f16611ee463..aa70d7e9fc1 100644
--- a/src/test/incremental/hashes/while_loops.rs
+++ b/src/test/incremental/hashes/while_loops.rs
@@ -36,9 +36,11 @@ fn change_loop_body() {
 }
 
 #[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")]
 fn change_loop_body() {
     let mut _x = 0;
@@ -61,9 +63,11 @@ fn change_loop_condition() {
 }
 
 #[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")]
 fn change_loop_condition() {
     let mut _x = 0;
@@ -85,9 +89,11 @@ fn add_break() {
 }
 
 #[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")]
 fn add_break() {
     let mut _x = 0;
@@ -110,9 +116,11 @@ fn add_loop_label() {
 }
 
 #[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")]
 fn add_loop_label() {
     let mut _x = 0;
@@ -135,9 +143,11 @@ fn add_loop_label_to_break() {
 }
 
 #[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")]
 fn add_loop_label_to_break() {
     let mut _x = 0;
@@ -162,9 +172,11 @@ fn change_break_label() {
 }
 
 #[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")]
 fn change_break_label() {
     let mut _x = 0;
@@ -189,9 +201,11 @@ fn add_loop_label_to_continue() {
 }
 
 #[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")]
 fn add_loop_label_to_continue() {
     let mut _x = 0;
@@ -216,9 +230,11 @@ fn change_continue_label() {
 }
 
 #[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")]
 fn change_continue_label() {
     let mut _x = 0;
@@ -243,9 +259,11 @@ fn change_continue_to_break() {
 }
 
 #[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")]
 fn change_continue_to_break() {
     let mut _x = 0;
diff --git a/src/test/incremental/hello_world.rs b/src/test/incremental/hello_world.rs
index a06c25ac055..b7f90c09b56 100644
--- a/src/test/incremental/hello_world.rs
+++ b/src/test/incremental/hello_world.rs
@@ -18,12 +18,12 @@ fn main() { }
 
 mod x {
     #[cfg(rpass1)]
-    pub fn x() -> i32 {
+    pub fn xxxx() -> i32 {
         1
     }
 
     #[cfg(rpass2)]
-    pub fn x() -> i32 {
+    pub fn xxxx() -> i32 {
         2
     }
 }
@@ -31,9 +31,9 @@ mod x {
 mod y {
     use x;
 
-    #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
-    pub fn y() {
-        x::x();
+    #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
+    pub fn yyyy() {
+        x::xxxx();
     }
 }
 
@@ -42,6 +42,6 @@ mod z {
 
     #[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
     pub fn z() {
-        y::y();
+        y::yyyy();
     }
 }
diff --git a/src/test/incremental/ich_method_call_trait_scope.rs b/src/test/incremental/ich_method_call_trait_scope.rs
index f28ecf74dd4..0a36e3c693e 100644
--- a/src/test/incremental/ich_method_call_trait_scope.rs
+++ b/src/test/incremental/ich_method_call_trait_scope.rs
@@ -46,12 +46,14 @@ mod mod3 {
 mod mod3 {
     use Trait2;
 
-    #[rustc_dirty(label="Hir", cfg="rpass2")]
+    #[rustc_clean(label="Hir", cfg="rpass2")]
+    #[rustc_dirty(label="HirBody", cfg="rpass2")]
     fn bar() {
         ().method();
     }
 
     #[rustc_clean(label="Hir", cfg="rpass2")]
+    #[rustc_clean(label="HirBody", cfg="rpass2")]
     fn baz() {
         22; // no method call, traits in scope don't matter
     }
diff --git a/src/test/incremental/ich_nested_items.rs b/src/test/incremental/ich_nested_items.rs
index 4466cfb1317..e8e40d57b1e 100644
--- a/src/test/incremental/ich_nested_items.rs
+++ b/src/test/incremental/ich_nested_items.rs
@@ -23,11 +23,14 @@ fn foo() {
 
 #[cfg(rpass2)]
 #[rustc_clean(label="Hir", cfg="rpass2")]
+#[rustc_clean(label="HirBody", cfg="rpass2")]
 fn foo() {
     #[rustc_clean(label="Hir", cfg="rpass2")]
+    #[rustc_clean(label="HirBody", cfg="rpass2")]
     fn baz() { } // order is different...
 
     #[rustc_clean(label="Hir", cfg="rpass2")]
+    #[rustc_clean(label="HirBody", cfg="rpass2")]
     fn bar() { } // but that doesn't matter.
 
     fn bap() { } // neither does adding a new item
diff --git a/src/test/incremental/ich_resolve_results.rs b/src/test/incremental/ich_resolve_results.rs
index 680a91da09f..49a88c530ff 100644
--- a/src/test/incremental/ich_resolve_results.rs
+++ b/src/test/incremental/ich_resolve_results.rs
@@ -45,11 +45,13 @@ mod mod3 {
     use test;
 
     #[rustc_clean(label="Hir", cfg="rpass2")]
+    #[rustc_clean(label="HirBody", cfg="rpass2")]
     fn in_expr() {
         Foo(0);
     }
 
     #[rustc_clean(label="Hir", cfg="rpass2")]
+    #[rustc_clean(label="HirBody", cfg="rpass2")]
     fn in_type() {
         test::<Foo>();
     }
@@ -60,12 +62,14 @@ mod mod3 {
     use test;
     use mod2::Foo; // <-- This changed!
 
-    #[rustc_dirty(label="Hir", cfg="rpass3")]
+    #[rustc_clean(label="Hir", cfg="rpass3")]
+    #[rustc_dirty(label="HirBody", cfg="rpass3")]
     fn in_expr() {
         Foo(0);
     }
 
-    #[rustc_dirty(label="Hir", cfg="rpass3")]
+    #[rustc_clean(label="Hir", cfg="rpass3")]
+    #[rustc_dirty(label="HirBody", cfg="rpass3")]
     fn in_type() {
         test::<Foo>();
     }
diff --git a/src/test/incremental/source_loc_macros.rs b/src/test/incremental/source_loc_macros.rs
index f922ac0da41..36d1b3ecbcd 100644
--- a/src/test/incremental/source_loc_macros.rs
+++ b/src/test/incremental/source_loc_macros.rs
@@ -18,16 +18,19 @@
 #![feature(rustc_attrs)]
 
 #[rustc_clean(label="Hir", cfg="rpass2")]
+#[rustc_clean(label="HirBody", cfg="rpass2")]
 fn line_same() {
     let _ = line!();
 }
 
 #[rustc_clean(label="Hir", cfg="rpass2")]
+#[rustc_clean(label="HirBody", cfg="rpass2")]
 fn col_same() {
     let _ = column!();
 }
 
 #[rustc_clean(label="Hir", cfg="rpass2")]
+#[rustc_clean(label="HirBody", cfg="rpass2")]
 fn file_same() {
     let _ = file!();
 }
@@ -38,7 +41,8 @@ fn line_different() {
 }
 
 #[cfg(rpass2)]
-#[rustc_dirty(label="Hir", cfg="rpass2")]
+#[rustc_clean(label="Hir", cfg="rpass2")]
+#[rustc_dirty(label="HirBody", cfg="rpass2")]
 fn line_different() {
     let _ = line!();
 }
@@ -49,7 +53,8 @@ fn col_different() {
 }
 
 #[cfg(rpass2)]
-#[rustc_dirty(label="Hir", cfg="rpass2")]
+#[rustc_clean(label="Hir", cfg="rpass2")]
+#[rustc_dirty(label="HirBody", cfg="rpass2")]
 fn col_different() {
     let _ =        column!();
 }
diff --git a/src/test/incremental/spans_insignificant_w_o_debuginfo.rs b/src/test/incremental/spans_insignificant_w_o_debuginfo.rs
index 9c8b8552498..90ec4a9d558 100644
--- a/src/test/incremental/spans_insignificant_w_o_debuginfo.rs
+++ b/src/test/incremental/spans_insignificant_w_o_debuginfo.rs
@@ -22,4 +22,5 @@ pub fn main() {}
 
 #[cfg(rpass2)]
 #[rustc_clean(label="Hir", cfg="rpass2")]
+#[rustc_clean(label="HirBody", cfg="rpass2")]
 pub fn main() {}
diff --git a/src/test/incremental/spans_significant_w_debuginfo.rs b/src/test/incremental/spans_significant_w_debuginfo.rs
index b0920aa1fa5..cdab8de9828 100644
--- a/src/test/incremental/spans_significant_w_debuginfo.rs
+++ b/src/test/incremental/spans_significant_w_debuginfo.rs
@@ -22,4 +22,5 @@ pub fn main() {}
 
 #[cfg(rpass2)]
 #[rustc_dirty(label="Hir", cfg="rpass2")]
+#[rustc_dirty(label="HirBody", cfg="rpass2")]
 pub fn main() {}
diff --git a/src/test/run-pass/associated-const-const-eval.rs b/src/test/run-pass/associated-const-const-eval.rs
new file mode 100644
index 00000000000..0b230df4146
--- /dev/null
+++ b/src/test/run-pass/associated-const-const-eval.rs
@@ -0,0 +1,30 @@
+// Copyright 2015 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.
+
+#![feature(associated_consts)]
+
+trait Foo {
+    const NUM: usize;
+}
+
+impl Foo for i32 {
+    const NUM: usize = 1;
+}
+
+const FOO: usize = <i32 as Foo>::NUM;
+
+fn main() {
+    assert_eq!(1, FOO);
+
+    match 1 {
+        <i32 as Foo>::NUM => {},
+        _ => assert!(false)
+    }
+}
diff --git a/src/test/run-pass/associated-const-cross-crate-const-eval.rs b/src/test/run-pass/associated-const-cross-crate-const-eval.rs
new file mode 100644
index 00000000000..7d31bb5b1a5
--- /dev/null
+++ b/src/test/run-pass/associated-const-cross-crate-const-eval.rs
@@ -0,0 +1,38 @@
+// Copyright 2015 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.
+
+// aux-build:associated-const-cc-lib.rs
+
+#![feature(associated_consts)]
+
+extern crate associated_const_cc_lib as foolib;
+
+pub struct LocalFoo;
+
+impl foolib::Foo for LocalFoo {
+    const BAR: usize = 1;
+}
+
+const FOO_1: usize = <foolib::FooNoDefault as foolib::Foo>::BAR;
+const FOO_2: usize = <LocalFoo as foolib::Foo>::BAR;
+const FOO_3: usize = foolib::InherentBar::BAR;
+
+fn main() {
+    assert_eq!(0, FOO_1);
+    assert_eq!(1, FOO_2);
+    assert_eq!(3, FOO_3);
+
+    match 0 {
+        <foolib::FooNoDefault as foolib::Foo>::BAR => {},
+        <LocalFoo as foolib::Foo>::BAR => assert!(false),
+        foolib::InherentBar::BAR => assert!(false),
+        _ => assert!(false)
+    }
+}