about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlorian Diebold <flodiebold@gmail.com>2016-10-28 22:58:32 +0200
committerFlorian Diebold <florian.diebold@freiheit.com>2016-11-29 13:04:27 +0100
commitf55482e7c965a7a4280fef968cb1cdd701c04ecc (patch)
tree44ca3f8edfe124b9508d4715af78bfa89985574e
parent069a2442b82a8f05882fea4f79b7514e32754697 (diff)
downloadrust-f55482e7c965a7a4280fef968cb1cdd701c04ecc.tar.gz
rust-f55482e7c965a7a4280fef968cb1cdd701c04ecc.zip
rustc: replace body exprs by their ids
-rw-r--r--src/librustc/hir/intravisit.rs105
-rw-r--r--src/librustc/hir/lowering.rs15
-rw-r--r--src/librustc/hir/map/blocks.rs28
-rw-r--r--src/librustc/hir/map/collector.rs11
-rw-r--r--src/librustc/hir/map/def_collector.rs6
-rw-r--r--src/librustc/hir/map/mod.rs4
-rw-r--r--src/librustc/hir/mod.rs12
-rw-r--r--src/librustc/hir/print.rs17
-rw-r--r--src/librustc/lint/context.rs25
-rw-r--r--src/librustc/middle/dead.rs35
-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.rs66
-rw-r--r--src/librustc/middle/mem_categorization.rs2
-rw-r--r--src/librustc/middle/reachable.rs26
-rw-r--r--src/librustc/middle/region.rs79
-rw-r--r--src/librustc/middle/resolve_lifetime.rs18
-rw-r--r--src/librustc/middle/stability.rs10
-rw-r--r--src/librustc/ty/mod.rs10
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs2
-rw-r--r--src/librustc_metadata/astencode.rs2
22 files changed, 327 insertions, 195 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 94da10d33f8..b5a6ba3555d 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -67,6 +67,14 @@ impl<'a> FnKind<'a> {
     }
 }
 
+/// Specifies what nested things a visitor wants to visit. Currently there are
+/// two modes: `OnlyBodies` descends into item bodies, but not into nested
+/// items; `All` descends into item bodies and nested items.
+pub enum NestedVisitMode {
+    OnlyBodies,
+    All
+}
+
 /// 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;
@@ -102,7 +110,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>> {
+    fn nested_visit_map(&mut self) -> Option<(&Map<'v>, NestedVisitMode)> {
         None
     }
 
@@ -116,7 +124,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()
+        let opt_item = map_for_item(self)
                            .map(|map| map.expect_item(id.id));
         if let Some(item) = opt_item {
             self.visit_item(item);
@@ -128,13 +136,25 @@ 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()
+        let opt_item = map_for_item(self)
                            .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 = map_for_body(self)
+                           .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 +220,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) {
@@ -279,6 +299,19 @@ pub trait Visitor<'v> : Sized {
     }
 }
 
+fn map_for_body<'v, V: Visitor<'v>>(visitor: &mut V) -> Option<&Map<'v>> {
+    visitor.nested_visit_map().map(|(map, _mode)| map)
+}
+
+fn map_for_item<'v, V: Visitor<'v>>(visitor: &mut V) -> Option<&Map<'v>> {
+    visitor.nested_visit_map().and_then(|(map, mode)| {
+        match mode {
+            NestedVisitMode::OnlyBodies => None,
+            NestedVisitMode::All => Some(map)
+        }
+    })
+}
+
 pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option<Name>) {
     if let Some(name) = opt_name {
         visitor.visit_name(span, name);
@@ -363,7 +396,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 +405,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 +730,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 +765,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 +797,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 +928,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 +1043,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 +1058,25 @@ impl IdRangeComputingVisitor {
     }
 }
 
-impl<'v> Visitor<'v> for IdRangeComputingVisitor {
+impl<'a, 'ast> Visitor<'ast> for IdRangeComputingVisitor<'a, 'ast> {
+    fn nested_visit_map(&mut self) -> Option<(&Map<'ast>, NestedVisitMode)> {
+        Some((&self.map, NestedVisitMode::OnlyBodies))
+    }
+
     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/lowering.rs b/src/librustc/hir/lowering.rs
index 7ea870e4300..ccf94e0b803 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -845,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)),
@@ -917,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) => {
@@ -945,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"),
@@ -1395,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..0adeb90e697 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)
     }
 
@@ -215,7 +215,7 @@ impl<'a> FnLikeNode<'a> {
                   Name,
                   &'a ast::MethodSig,
                   Option<&'a ast::Visibility>,
-                  &'a ast::Expr,
+                  ast::ExprId,
                   Span,
                   &'a [Attribute])
                   -> A,
@@ -223,13 +223,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,14 +240,14 @@ 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)
                     }
                     _ => {
@@ -256,8 +256,8 @@ impl<'a> FnLikeNode<'a> {
                 }
             }
             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..6033278575d 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -10,7 +10,8 @@
 
 use super::*;
 
-use hir::intravisit::Visitor;
+use hir::*;
+use hir::intravisit::{Visitor, NestedVisitMode};
 use hir::def_id::DefId;
 use middle::cstore::InlinedItem;
 use std::iter::repeat;
@@ -91,7 +92,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(&mut self) -> Option<(&map::Map<'ast>, NestedVisitMode)> {
         panic!("visit_nested_xxx must be manually implemented in this visitor")
     }
 
@@ -106,6 +107,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 +214,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..a6d7c79e346 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -327,6 +327,12 @@ 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> {
+    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..7ef98fcce7e 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -655,6 +655,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) {
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index eda8e34516e..f66e6788ee7 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -460,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.
@@ -925,7 +929,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>),
 
@@ -1079,7 +1083,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>>),
@@ -1112,7 +1116,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>),
 }
@@ -1557,7 +1561,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..799c7e0cc84 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(&mut self) -> Option<(&hir::map::Map<'tcx>, hir_visit::NestedVisitMode)> {
+        Some((&self.tcx.map, hir_visit::NestedVisitMode::All))
     }
 
     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(&mut self) -> Option<(&hir::map::Map<'tcx>, hir_visit::NestedVisitMode)> {
+        Some((&self.cx.tcx.map, hir_visit::NestedVisitMode::OnlyBodies))
+    }
+
     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/dead.rs b/src/librustc/middle/dead.rs
index 618e2b05f13..575ac9773a7 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, NestedVisitMode};
 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(&mut self) -> Option<(&hir::map::Map<'tcx>, NestedVisitMode)> {
+        Some((&self.tcx.map, NestedVisitMode::OnlyBodies))
+    }
 
-    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,8 +291,8 @@ 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) {
-        self.handle_definition(id, path.def);
+    fn visit_path(&mut self, path: &'tcx hir::Path, id: ast::NodeId) {
+        self.lookup_and_handle_definition(id);
         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(&mut self) -> Option<(&hir::map::Map<'tcx>, NestedVisitMode)> {
+        Some((&self.tcx.map, NestedVisitMode::All))
     }
 
     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..57735b91ac5 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, NestedVisitMode};
 
 #[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(&mut self) -> Option<(&hir::map::Map<'tcx>, NestedVisitMode)> {
+        Some((&self.tcx.map, NestedVisitMode::OnlyBodies))
+    }
+
+    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..5673ec05cf9 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, NestedVisitMode};
 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(&mut self) -> Option<(&hir::map::Map<'tcx>, NestedVisitMode)> {
+        Some((&self.tcx.map, NestedVisitMode::OnlyBodies))
+    }
+
     // 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(&mut self) -> Option<(&hir::map::Map<'gcx>, NestedVisitMode)> {
+        Some((&self.infcx.tcx.map, NestedVisitMode::OnlyBodies))
+    }
+
+    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..ca28f1dae29 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, NestedVisitMode};
 
 /// For use with `propagate_through_loop`.
 enum LoopKind<'a> {
@@ -182,14 +182,17 @@ 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(&mut self) -> Option<(&hir::map::Map<'tcx>, NestedVisitMode)> {
+        Some((&self.tcx.map, NestedVisitMode::OnlyBodies))
+    }
+    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 +351,31 @@ 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(&mut self) -> Option<(&hir::map::Map<'tcx>, NestedVisitMode)> {
+        Some((&self.ir.tcx.map, NestedVisitMode::OnlyBodies))
+    }
+    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 +393,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 +406,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 +418,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 +431,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 +447,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 +931,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 +940,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 +1362,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 +1377,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 +1387,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 +1477,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..f8a1b109d9d 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, NestedVisitMode};
 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(&mut self) -> Option<(&hir::map::Map<'tcx>, NestedVisitMode)> {
+        Some((&self.tcx.map, NestedVisitMode::OnlyBodies))
+    }
+
+    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..49a2b4f17ed 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, NestedVisitMode};
 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,7 @@ 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 +1065,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 +1080,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 +1121,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 +1168,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(&mut self) -> Option<(&hir::map::Map<'ast>, NestedVisitMode)> {
+        Some((&self.map, NestedVisitMode::OnlyBodies))
+    }
+
+    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 +1234,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..7b94f9b32d9 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, NestedVisitMode};
 
 #[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(&mut self) -> Option<(&hir::map::Map<'tcx>, NestedVisitMode)> {
+        Some((&self.hir_map, NestedVisitMode::All))
     }
 
     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,7 +419,7 @@ 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> {
@@ -497,7 +497,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 +518,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
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index f5e18e13465..7417509e5b7 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -30,7 +30,7 @@ use util::nodemap::{DefIdMap, FxHashSet, FxHashMap};
 
 use hir;
 use hir::{Item, Generics, StructField, Variant};
-use hir::intravisit::{self, Visitor};
+use hir::intravisit::{self, Visitor, NestedVisitMode};
 use hir::itemlikevisit::DeepVisitor;
 
 use std::mem::replace;
@@ -234,8 +234,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(&mut self) -> Option<(&hir::map::Map<'tcx>, NestedVisitMode)> {
+        Some((&self.tcx.map, NestedVisitMode::All))
     }
 
     fn visit_item(&mut self, i: &'tcx Item) {
@@ -534,6 +534,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
+    fn nested_visit_map(&mut self) -> Option<(&hir::map::Map<'tcx>, NestedVisitMode)> {
+        Some((&self.tcx.map, NestedVisitMode::OnlyBodies))
+    }
+
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         match item.node {
             hir::ItemExternCrate(_) => {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 844fc58cec3..16f84a1b8aa 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(..) |
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 5e54e333bb9..f1ffd2b3f09 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -205,7 +205,7 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'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);
 
diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs
index 806d20c72dc..1434181075f 100644
--- a/src/librustc_metadata/astencode.rs
+++ b/src/librustc_metadata/astencode.rs
@@ -44,7 +44,7 @@ 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();
+        let mut id_visitor = IdRangeComputingVisitor::new(&self.tcx.map);
         match ii {
             InlinedItemRef::Item(_, i) => id_visitor.visit_item(i),
             InlinedItemRef::TraitItem(_, ti) => id_visitor.visit_trait_item(ti),