From 28ddd7a4ef30a89091dbf48cae18f571326510fb Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Tue, 29 Aug 2017 19:27:30 +0300
Subject: [PATCH 1/3] rustc: use hir::ItemLocalId instead of ast::NodeId in
 CFG.

---
 src/librustc/cfg/construct.rs                 | 89 +++++++++--------
 src/librustc/cfg/graphviz.rs                  | 63 ++++++------
 src/librustc/cfg/mod.rs                       | 13 +--
 src/librustc/hir/map/mod.rs                   | 15 ++-
 src/librustc/middle/dataflow.rs               | 96 ++++++++++---------
 src/librustc_borrowck/borrowck/check_loans.rs | 60 +++++++-----
 .../borrowck/gather_loans/gather_moves.rs     | 15 +--
 .../borrowck/gather_loans/mod.rs              | 12 ++-
 src/librustc_borrowck/borrowck/mod.rs         | 17 ++--
 src/librustc_borrowck/borrowck/move_data.rs   | 55 +++++------
 src/librustc_borrowck/graphviz.rs             |  2 +-
 src/librustc_driver/pretty.rs                 |  2 +-
 src/librustc_lint/builtin.rs                  | 26 ++---
 13 files changed, 249 insertions(+), 216 deletions(-)

diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index e7e2c84fc4efa..1448fb7c528c6 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -12,7 +12,6 @@ use rustc_data_structures::graph;
 use cfg::*;
 use middle::region::CodeExtent;
 use ty::{self, TyCtxt};
-use syntax::ast;
 use syntax::ptr::P;
 
 use hir::{self, PatKind};
@@ -30,13 +29,13 @@ struct CFGBuilder<'a, 'tcx: 'a> {
 
 #[derive(Copy, Clone)]
 struct BlockScope {
-    block_expr_id: ast::NodeId, // id of breakable block expr node
+    block_expr_id: hir::ItemLocalId, // id of breakable block expr node
     break_index: CFGIndex, // where to go on `break`
 }
 
 #[derive(Copy, Clone)]
 struct LoopScope {
-    loop_id: ast::NodeId,     // id of loop/while node
+    loop_id: hir::ItemLocalId,     // id of loop/while node
     continue_index: CFGIndex, // where to go on a `loop`
     break_index: CFGIndex,    // where to go on a `break`
 }
@@ -70,6 +69,7 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     cfg_builder.add_contained_edge(body_exit, fn_exit);
     let CFGBuilder { graph, .. } = cfg_builder;
     CFG {
+        owner_def_id,
         graph,
         entry,
         exit: fn_exit,
@@ -79,10 +79,10 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
     fn block(&mut self, blk: &hir::Block, pred: CFGIndex) -> CFGIndex {
         if blk.targeted_by_break {
-            let expr_exit = self.add_ast_node(blk.id, &[]);
+            let expr_exit = self.add_ast_node(blk.hir_id.local_id, &[]);
 
             self.breakable_block_scopes.push(BlockScope {
-                block_expr_id: blk.id,
+                block_expr_id: blk.hir_id.local_id,
                 break_index: expr_exit,
             });
 
@@ -104,21 +104,22 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
 
             let expr_exit = self.opt_expr(&blk.expr, stmts_exit);
 
-            self.add_ast_node(blk.id, &[expr_exit])
+            self.add_ast_node(blk.hir_id.local_id, &[expr_exit])
         }
     }
 
     fn stmt(&mut self, stmt: &hir::Stmt, pred: CFGIndex) -> CFGIndex {
+        let hir_id = self.tcx.hir.node_to_hir_id(stmt.node.id());
         match stmt.node {
-            hir::StmtDecl(ref decl, id) => {
+            hir::StmtDecl(ref decl, _) => {
                 let exit = self.decl(&decl, pred);
-                self.add_ast_node(id, &[exit])
+                self.add_ast_node(hir_id.local_id, &[exit])
             }
 
-            hir::StmtExpr(ref expr, id) |
-            hir::StmtSemi(ref expr, id) => {
+            hir::StmtExpr(ref expr, _) |
+            hir::StmtSemi(ref expr, _) => {
                 let exit = self.expr(&expr, pred);
-                self.add_ast_node(id, &[exit])
+                self.add_ast_node(hir_id.local_id, &[exit])
             }
         }
     }
@@ -140,31 +141,31 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             PatKind::Path(_) |
             PatKind::Lit(..) |
             PatKind::Range(..) |
-            PatKind::Wild => self.add_ast_node(pat.id, &[pred]),
+            PatKind::Wild => self.add_ast_node(pat.hir_id.local_id, &[pred]),
 
             PatKind::Box(ref subpat) |
             PatKind::Ref(ref subpat, _) |
             PatKind::Binding(.., Some(ref subpat)) => {
                 let subpat_exit = self.pat(&subpat, pred);
-                self.add_ast_node(pat.id, &[subpat_exit])
+                self.add_ast_node(pat.hir_id.local_id, &[subpat_exit])
             }
 
             PatKind::TupleStruct(_, ref subpats, _) |
             PatKind::Tuple(ref subpats, _) => {
                 let pats_exit = self.pats_all(subpats.iter(), pred);
-                self.add_ast_node(pat.id, &[pats_exit])
+                self.add_ast_node(pat.hir_id.local_id, &[pats_exit])
             }
 
             PatKind::Struct(_, ref subpats, _) => {
                 let pats_exit = self.pats_all(subpats.iter().map(|f| &f.node.pat), pred);
-                self.add_ast_node(pat.id, &[pats_exit])
+                self.add_ast_node(pat.hir_id.local_id, &[pats_exit])
             }
 
             PatKind::Slice(ref pre, ref vec, ref post) => {
                 let pre_exit = self.pats_all(pre.iter(), pred);
                 let vec_exit = self.pats_all(vec.iter(), pre_exit);
                 let post_exit = self.pats_all(post.iter(), vec_exit);
-                self.add_ast_node(pat.id, &[post_exit])
+                self.add_ast_node(pat.hir_id.local_id, &[post_exit])
             }
         }
     }
@@ -180,7 +181,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
         match expr.node {
             hir::ExprBlock(ref blk) => {
                 let blk_exit = self.block(&blk, pred);
-                self.add_ast_node(expr.id, &[blk_exit])
+                self.add_ast_node(expr.hir_id.local_id, &[blk_exit])
             }
 
             hir::ExprIf(ref cond, ref then, None) => {
@@ -200,7 +201,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                 //
                 let cond_exit = self.expr(&cond, pred);                // 1
                 let then_exit = self.expr(&then, cond_exit);          // 2
-                self.add_ast_node(expr.id, &[cond_exit, then_exit])      // 3,4
+                self.add_ast_node(expr.hir_id.local_id, &[cond_exit, then_exit])      // 3,4
             }
 
             hir::ExprIf(ref cond, ref then, Some(ref otherwise)) => {
@@ -221,7 +222,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                 let cond_exit = self.expr(&cond, pred);                // 1
                 let then_exit = self.expr(&then, cond_exit);          // 2
                 let else_exit = self.expr(&otherwise, cond_exit);      // 3
-                self.add_ast_node(expr.id, &[then_exit, else_exit])      // 4, 5
+                self.add_ast_node(expr.hir_id.local_id, &[then_exit, else_exit])      // 4, 5
             }
 
             hir::ExprWhile(ref cond, ref body, _) => {
@@ -245,12 +246,12 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                 let loopback = self.add_dummy_node(&[pred]);              // 1
 
                 // Create expr_exit without pred (cond_exit)
-                let expr_exit = self.add_ast_node(expr.id, &[]);         // 3
+                let expr_exit = self.add_ast_node(expr.hir_id.local_id, &[]);         // 3
 
                 // The LoopScope needs to be on the loop_scopes stack while evaluating the
                 // condition and the body of the loop (both can break out of the loop)
                 self.loop_scopes.push(LoopScope {
-                    loop_id: expr.id,
+                    loop_id: expr.hir_id.local_id,
                     continue_index: loopback,
                     break_index: expr_exit
                 });
@@ -282,9 +283,9 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                 // may cause additional edges.
 
                 let loopback = self.add_dummy_node(&[pred]);              // 1
-                let expr_exit = self.add_ast_node(expr.id, &[]);          // 2
+                let expr_exit = self.add_ast_node(expr.hir_id.local_id, &[]);          // 2
                 self.loop_scopes.push(LoopScope {
-                    loop_id: expr.id,
+                    loop_id: expr.hir_id.local_id,
                     continue_index: loopback,
                     break_index: expr_exit,
                 });
@@ -295,7 +296,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             }
 
             hir::ExprMatch(ref discr, ref arms, _) => {
-                self.match_(expr.id, &discr, &arms, pred)
+                self.match_(expr.hir_id.local_id, &discr, &arms, pred)
             }
 
             hir::ExprBinary(op, ref l, ref r) if op.node.is_lazy() => {
@@ -315,30 +316,30 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                 //
                 let l_exit = self.expr(&l, pred);                      // 1
                 let r_exit = self.expr(&r, l_exit);                    // 2
-                self.add_ast_node(expr.id, &[l_exit, r_exit])            // 3,4
+                self.add_ast_node(expr.hir_id.local_id, &[l_exit, r_exit])            // 3,4
             }
 
             hir::ExprRet(ref v) => {
                 let v_exit = self.opt_expr(v, pred);
-                let b = self.add_ast_node(expr.id, &[v_exit]);
+                let b = self.add_ast_node(expr.hir_id.local_id, &[v_exit]);
                 self.add_returning_edge(expr, b);
                 self.add_unreachable_node()
             }
 
             hir::ExprBreak(destination, ref opt_expr) => {
                 let v = self.opt_expr(opt_expr, pred);
-                let (scope_id, break_dest) =
+                let (target_scope, break_dest) =
                     self.find_scope_edge(expr, destination, ScopeCfKind::Break);
-                let b = self.add_ast_node(expr.id, &[v]);
-                self.add_exiting_edge(expr, b, scope_id, break_dest);
+                let b = self.add_ast_node(expr.hir_id.local_id, &[v]);
+                self.add_exiting_edge(expr, b, target_scope, break_dest);
                 self.add_unreachable_node()
             }
 
             hir::ExprAgain(destination) => {
-                let (scope_id, cont_dest) =
+                let (target_scope, cont_dest) =
                     self.find_scope_edge(expr, destination, ScopeCfKind::Continue);
-                let a = self.add_ast_node(expr.id, &[pred]);
-                self.add_exiting_edge(expr, a, scope_id, cont_dest);
+                let a = self.add_ast_node(expr.hir_id.local_id, &[pred]);
+                self.add_exiting_edge(expr, a, target_scope, cont_dest);
                 self.add_unreachable_node()
             }
 
@@ -397,7 +398,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
                 let post_outputs = self.exprs(outputs.iter().map(|e| &*e), pred);
                 let post_inputs = self.exprs(inputs.iter().map(|e| &*e), post_outputs);
-                self.add_ast_node(expr.id, &[post_inputs])
+                self.add_ast_node(expr.hir_id.local_id, &[post_inputs])
             }
 
             hir::ExprClosure(..) |
@@ -444,10 +445,10 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
         //! Handles case of an expression that evaluates `subexprs` in order
 
         let subexprs_exit = self.exprs(subexprs, pred);
-        self.add_ast_node(expr.id, &[subexprs_exit])
+        self.add_ast_node(expr.hir_id.local_id, &[subexprs_exit])
     }
 
-    fn match_(&mut self, id: ast::NodeId, discr: &hir::Expr,
+    fn match_(&mut self, id: hir::ItemLocalId, discr: &hir::Expr,
               arms: &[hir::Arm], pred: CFGIndex) -> CFGIndex {
         // The CFG for match expression is quite complex, so no ASCII
         // art for it (yet).
@@ -552,8 +553,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
         self.add_node(CFGNodeData::Dummy, preds)
     }
 
-    fn add_ast_node(&mut self, id: ast::NodeId, preds: &[CFGIndex]) -> CFGIndex {
-        assert!(id != ast::DUMMY_NODE_ID);
+    fn add_ast_node(&mut self, id: hir::ItemLocalId, preds: &[CFGIndex]) -> CFGIndex {
         self.add_node(CFGNodeData::AST(id), preds)
     }
 
@@ -579,14 +579,13 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
     fn add_exiting_edge(&mut self,
                         from_expr: &hir::Expr,
                         from_index: CFGIndex,
-                        scope_id: ast::NodeId,
+                        target_scope: CodeExtent,
                         to_index: CFGIndex) {
         let mut data = CFGEdgeData { exiting_scopes: vec![] };
         let mut scope = CodeExtent::Misc(from_expr.id);
-        let target_scope = CodeExtent::Misc(scope_id);
         let region_maps = self.tcx.region_maps(self.owner_def_id);
         while scope != target_scope {
-            data.exiting_scopes.push(scope.node_id());
+            data.exiting_scopes.push(self.tcx.hir.node_to_hir_id(scope.node_id()).local_id);
             scope = region_maps.encl_scope(scope);
         }
         self.graph.add_edge(from_index, to_index, data);
@@ -607,13 +606,13 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
     fn find_scope_edge(&self,
                   expr: &hir::Expr,
                   destination: hir::Destination,
-                  scope_cf_kind: ScopeCfKind) -> (ast::NodeId, CFGIndex) {
+                  scope_cf_kind: ScopeCfKind) -> (CodeExtent, CFGIndex) {
 
         match destination.target_id {
             hir::ScopeTarget::Block(block_expr_id) => {
                 for b in &self.breakable_block_scopes {
-                    if b.block_expr_id == block_expr_id {
-                        return (block_expr_id, match scope_cf_kind {
+                    if b.block_expr_id == self.tcx.hir.node_to_hir_id(block_expr_id).local_id {
+                        return (CodeExtent::Misc(block_expr_id), match scope_cf_kind {
                             ScopeCfKind::Break => b.break_index,
                             ScopeCfKind::Continue => bug!("can't continue to block"),
                         });
@@ -623,8 +622,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             }
             hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(loop_id)) => {
                 for l in &self.loop_scopes {
-                    if l.loop_id == loop_id {
-                        return (loop_id, match scope_cf_kind {
+                    if l.loop_id == self.tcx.hir.node_to_hir_id(loop_id).local_id {
+                        return (CodeExtent::Misc(loop_id), match scope_cf_kind {
                             ScopeCfKind::Break => l.break_index,
                             ScopeCfKind::Continue => l.continue_index,
                         });
diff --git a/src/librustc/cfg/graphviz.rs b/src/librustc/cfg/graphviz.rs
index 944b77dbf01fd..fa034744b62e2 100644
--- a/src/librustc/cfg/graphviz.rs
+++ b/src/librustc/cfg/graphviz.rs
@@ -15,40 +15,47 @@
 use graphviz as dot;
 use graphviz::IntoCow;
 
-use syntax::ast;
-
-use hir::map as hir_map;
 use cfg;
+use hir;
+use ty::TyCtxt;
 
 pub type Node<'a> = (cfg::CFGIndex, &'a cfg::CFGNode);
 pub type Edge<'a> = &'a cfg::CFGEdge;
 
-pub struct LabelledCFG<'a, 'hir: 'a> {
-    pub hir_map: &'a hir_map::Map<'hir>,
+pub struct LabelledCFG<'a, 'tcx: 'a> {
+    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
     pub cfg: &'a cfg::CFG,
     pub name: String,
     /// `labelled_edges` controls whether we emit labels on the edges
     pub labelled_edges: bool,
 }
 
-fn replace_newline_with_backslash_l(s: String) -> String {
-    // Replacing newlines with \\l causes each line to be left-aligned,
-    // improving presentation of (long) pretty-printed expressions.
-    if s.contains("\n") {
-        let mut s = s.replace("\n", "\\l");
-        // Apparently left-alignment applies to the line that precedes
-        // \l, not the line that follows; so, add \l at end of string
-        // if not already present, ensuring last line gets left-aligned
-        // as well.
-        let mut last_two: Vec<_> =
-            s.chars().rev().take(2).collect();
-        last_two.reverse();
-        if last_two != ['\\', 'l'] {
-            s.push_str("\\l");
+impl<'a, 'tcx> LabelledCFG<'a, 'tcx> {
+    fn local_id_to_string(&self, local_id: hir::ItemLocalId) -> String {
+        let node_id = self.tcx.hir.hir_to_node_id(hir::HirId {
+            owner: self.tcx.closure_base_def_id(self.cfg.owner_def_id).index,
+            local_id
+        });
+        let s = self.tcx.hir.node_to_string(node_id);
+
+        // Replacing newlines with \\l causes each line to be left-aligned,
+        // improving presentation of (long) pretty-printed expressions.
+        if s.contains("\n") {
+            let mut s = s.replace("\n", "\\l");
+            // Apparently left-alignment applies to the line that precedes
+            // \l, not the line that follows; so, add \l at end of string
+            // if not already present, ensuring last line gets left-aligned
+            // as well.
+            let mut last_two: Vec<_> =
+                s.chars().rev().take(2).collect();
+            last_two.reverse();
+            if last_two != ['\\', 'l'] {
+                s.push_str("\\l");
+            }
+            s
+        } else {
+            s
         }
-        s
-    } else {
-        s
     }
 }
 
@@ -66,12 +73,10 @@ impl<'a, 'hir> dot::Labeller<'a> for LabelledCFG<'a, 'hir> {
             dot::LabelText::LabelStr("entry".into_cow())
         } else if i == self.cfg.exit {
             dot::LabelText::LabelStr("exit".into_cow())
-        } else if n.data.id() == ast::DUMMY_NODE_ID {
+        } else if n.data.id() == hir::DUMMY_ITEM_LOCAL_ID {
             dot::LabelText::LabelStr("(dummy_node)".into_cow())
         } else {
-            let s = self.hir_map.node_to_string(n.data.id());
-            // left-aligns the lines
-            let s = replace_newline_with_backslash_l(s);
+            let s = self.local_id_to_string(n.data.id());
             dot::LabelText::EscStr(s.into_cow())
         }
     }
@@ -82,15 +87,13 @@ impl<'a, 'hir> dot::Labeller<'a> for LabelledCFG<'a, 'hir> {
             return dot::LabelText::EscStr(label.into_cow());
         }
         let mut put_one = false;
-        for (i, &node_id) in e.data.exiting_scopes.iter().enumerate() {
+        for (i, &id) in e.data.exiting_scopes.iter().enumerate() {
             if put_one {
                 label.push_str(",\\l");
             } else {
                 put_one = true;
             }
-            let s = self.hir_map.node_to_string(node_id);
-            // left-aligns the lines
-            let s = replace_newline_with_backslash_l(s);
+            let s = self.local_id_to_string(id);
             label.push_str(&format!("exiting scope_{} {}",
                                    i,
                                    &s[..]));
diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs
index 1473dbb1676f3..b379d3956e944 100644
--- a/src/librustc/cfg/mod.rs
+++ b/src/librustc/cfg/mod.rs
@@ -13,13 +13,14 @@
 
 use rustc_data_structures::graph;
 use ty::TyCtxt;
-use syntax::ast;
 use hir;
+use hir::def_id::DefId;
 
 mod construct;
 pub mod graphviz;
 
 pub struct CFG {
+    pub owner_def_id: DefId,
     pub graph: CFGGraph,
     pub entry: CFGIndex,
     pub exit: CFGIndex,
@@ -27,7 +28,7 @@ pub struct CFG {
 
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub enum CFGNodeData {
-    AST(ast::NodeId),
+    AST(hir::ItemLocalId),
     Entry,
     Exit,
     Dummy,
@@ -35,18 +36,18 @@ pub enum CFGNodeData {
 }
 
 impl CFGNodeData {
-    pub fn id(&self) -> ast::NodeId {
+    pub fn id(&self) -> hir::ItemLocalId {
         if let CFGNodeData::AST(id) = *self {
             id
         } else {
-            ast::DUMMY_NODE_ID
+            hir::DUMMY_ITEM_LOCAL_ID
         }
     }
 }
 
 #[derive(Debug)]
 pub struct CFGEdgeData {
-    pub exiting_scopes: Vec<ast::NodeId>
+    pub exiting_scopes: Vec<hir::ItemLocalId>
 }
 
 pub type CFGIndex = graph::NodeIndex;
@@ -63,7 +64,7 @@ impl CFG {
         construct::construct(tcx, body)
     }
 
-    pub fn node_is_reachable(&self, id: ast::NodeId) -> bool {
+    pub fn node_is_reachable(&self, id: hir::ItemLocalId) -> bool {
         self.graph.depth_traverse(self.entry, graph::OUTGOING)
                   .any(|idx| self.graph.node_data(idx).id() == id)
     }
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 31b0b5c820e3d..e54df2d50d8eb 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -26,7 +26,7 @@ use syntax_pos::Span;
 
 use hir::*;
 use hir::print::Nested;
-use util::nodemap::DefIdMap;
+use util::nodemap::{DefIdMap, FxHashMap};
 
 use arena::TypedArena;
 use std::cell::RefCell;
@@ -251,6 +251,9 @@ pub struct Map<'hir> {
 
     /// Bodies inlined from other crates are cached here.
     inlined_bodies: RefCell<DefIdMap<&'hir Body>>,
+
+    /// The reverse mapping of `node_to_hir_id`.
+    hir_to_node_id: FxHashMap<HirId, NodeId>,
 }
 
 impl<'hir> Map<'hir> {
@@ -339,6 +342,11 @@ impl<'hir> Map<'hir> {
         self.definitions.as_local_node_id(def_id)
     }
 
+    #[inline]
+    pub fn hir_to_node_id(&self, hir_id: HirId) -> NodeId {
+        self.hir_to_node_id[&hir_id]
+    }
+
     #[inline]
     pub fn node_to_hir_id(&self, node_id: NodeId) -> HirId {
         self.definitions.node_to_hir_id(node_id)
@@ -1021,10 +1029,15 @@ pub fn map_crate<'hir>(forest: &'hir mut Forest,
               entries, vector_length, (entries as f64 / vector_length as f64) * 100.);
     }
 
+    // Build the reverse mapping of `node_to_hir_id`.
+    let hir_to_node_id = definitions.node_to_hir_id.iter_enumerated()
+        .map(|(node_id, &hir_id)| (hir_id, node_id)).collect();
+
     let map = Map {
         forest,
         dep_graph: forest.dep_graph.clone(),
         map,
+        hir_to_node_id,
         definitions,
         inlined_bodies: RefCell::new(DefIdMap()),
     };
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index d394c0f0c8734..e88678dea1d74 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -20,12 +20,11 @@ use ty::TyCtxt;
 use std::io;
 use std::mem;
 use std::usize;
-use syntax::ast;
 use syntax::print::pprust::PrintState;
 
 use rustc_data_structures::graph::OUTGOING;
 
-use util::nodemap::NodeMap;
+use util::nodemap::FxHashMap;
 use hir;
 use hir::intravisit::{self, IdRange};
 use hir::print as pprust;
@@ -56,7 +55,7 @@ pub struct DataFlowContext<'a, 'tcx: 'a, O> {
 
     // mapping from node to cfg node index
     // FIXME (#6298): Shouldn't this go with CFG?
-    nodeid_to_index: NodeMap<Vec<CFGIndex>>,
+    local_id_to_index: FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>,
 
     // Bit sets per cfg node.  The following three fields (`gens`, `kills`,
     // and `on_entry`) all have the same structure. For each id in
@@ -97,15 +96,16 @@ struct PropagationContext<'a, 'b: 'a, 'tcx: 'b, O: 'a> {
     changed: bool
 }
 
-fn get_cfg_indices<'a>(id: ast::NodeId, index: &'a NodeMap<Vec<CFGIndex>>) -> &'a [CFGIndex] {
-    let opt_indices = index.get(&id);
-    opt_indices.map(|v| &v[..]).unwrap_or(&[])
+fn get_cfg_indices<'a>(id: hir::ItemLocalId,
+                       index: &'a FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>)
+                       -> &'a [CFGIndex] {
+    index.get(&id).map_or(&[], |v| &v[..])
 }
 
 impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
-    fn has_bitset_for_nodeid(&self, n: ast::NodeId) -> bool {
-        assert!(n != ast::DUMMY_NODE_ID);
-        self.nodeid_to_index.contains_key(&n)
+    fn has_bitset_for_local_id(&self, n: hir::ItemLocalId) -> bool {
+        assert!(n != hir::DUMMY_ITEM_LOCAL_ID);
+        self.local_id_to_index.contains_key(&n)
     }
 }
 
@@ -117,19 +117,20 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O
            ps: &mut pprust::State,
            node: pprust::AnnNode) -> io::Result<()> {
         let id = match node {
-            pprust::NodeName(_) => ast::CRATE_NODE_ID,
-            pprust::NodeExpr(expr) => expr.id,
-            pprust::NodeBlock(blk) => blk.id,
-            pprust::NodeItem(_) | pprust::NodeSubItem(_) => ast::CRATE_NODE_ID,
-            pprust::NodePat(pat) => pat.id
+            pprust::NodeName(_) => return Ok(()),
+            pprust::NodeExpr(expr) => expr.hir_id.local_id,
+            pprust::NodeBlock(blk) => blk.hir_id.local_id,
+            pprust::NodeItem(_) |
+            pprust::NodeSubItem(_) => return Ok(()),
+            pprust::NodePat(pat) => pat.hir_id.local_id
         };
 
-        if !self.has_bitset_for_nodeid(id) {
+        if !self.has_bitset_for_local_id(id) {
             return Ok(());
         }
 
         assert!(self.bits_per_id > 0);
-        let indices = get_cfg_indices(id, &self.nodeid_to_index);
+        let indices = get_cfg_indices(id, &self.local_id_to_index);
         for &cfgidx in indices {
             let (start, end) = self.compute_id_range(cfgidx);
             let on_entry = &self.on_entry[start.. end];
@@ -157,7 +158,7 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O
             };
 
             ps.synth_comment(
-                format!("id {}: {}{}{}{}", id, entry_str,
+                format!("id {}: {}{}{}{}", id.as_usize(), entry_str,
                         gens_str, action_kills_str, scope_kills_str))?;
             ps.s.space()?;
         }
@@ -165,9 +166,10 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O
     }
 }
 
-fn build_nodeid_to_index(body: Option<&hir::Body>,
-                         cfg: &cfg::CFG) -> NodeMap<Vec<CFGIndex>> {
-    let mut index = NodeMap();
+fn build_local_id_to_index(body: Option<&hir::Body>,
+                           cfg: &cfg::CFG)
+                           -> FxHashMap<hir::ItemLocalId, Vec<CFGIndex>> {
+    let mut index = FxHashMap();
 
     // FIXME (#6298): Would it be better to fold formals from decl
     // into cfg itself?  i.e. introduce a fn-based flow-graph in
@@ -188,14 +190,14 @@ fn build_nodeid_to_index(body: Option<&hir::Body>,
 
     /// Add mappings from the ast nodes for the formal bindings to
     /// the entry-node in the graph.
-    fn add_entries_from_fn_body(index: &mut NodeMap<Vec<CFGIndex>>,
+    fn add_entries_from_fn_body(index: &mut FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>,
                                 body: &hir::Body,
                                 entry: CFGIndex) {
         use hir::intravisit::Visitor;
 
         struct Formals<'a> {
             entry: CFGIndex,
-            index: &'a mut NodeMap<Vec<CFGIndex>>,
+            index: &'a mut FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>,
         }
         let mut formals = Formals { entry: entry, index: index };
         for arg in &body.arguments {
@@ -207,7 +209,7 @@ fn build_nodeid_to_index(body: Option<&hir::Body>,
             }
 
             fn visit_pat(&mut self, p: &hir::Pat) {
-                self.index.entry(p.id).or_insert(vec![]).push(self.entry);
+                self.index.entry(p.hir_id.local_id).or_insert(vec![]).push(self.entry);
                 intravisit::walk_pat(self, p)
             }
         }
@@ -259,13 +261,13 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
         let kills2 = zeroes;
         let on_entry = vec![entry; num_nodes * words_per_id];
 
-        let nodeid_to_index = build_nodeid_to_index(body, cfg);
+        let local_id_to_index = build_local_id_to_index(body, cfg);
 
         DataFlowContext {
             tcx,
             analysis_name,
             words_per_id,
-            nodeid_to_index,
+            local_id_to_index,
             bits_per_id,
             oper,
             gens,
@@ -275,14 +277,14 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
         }
     }
 
-    pub fn add_gen(&mut self, id: ast::NodeId, bit: usize) {
+    pub fn add_gen(&mut self, id: hir::ItemLocalId, bit: usize) {
         //! Indicates that `id` generates `bit`
-        debug!("{} add_gen(id={}, bit={})",
+        debug!("{} add_gen(id={:?}, bit={})",
                self.analysis_name, id, bit);
-        assert!(self.nodeid_to_index.contains_key(&id));
+        assert!(self.local_id_to_index.contains_key(&id));
         assert!(self.bits_per_id > 0);
 
-        let indices = get_cfg_indices(id, &self.nodeid_to_index);
+        let indices = get_cfg_indices(id, &self.local_id_to_index);
         for &cfgidx in indices {
             let (start, end) = self.compute_id_range(cfgidx);
             let gens = &mut self.gens[start.. end];
@@ -290,14 +292,14 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
         }
     }
 
-    pub fn add_kill(&mut self, kind: KillFrom, id: ast::NodeId, bit: usize) {
+    pub fn add_kill(&mut self, kind: KillFrom, id: hir::ItemLocalId, bit: usize) {
         //! Indicates that `id` kills `bit`
-        debug!("{} add_kill(id={}, bit={})",
+        debug!("{} add_kill(id={:?}, bit={})",
                self.analysis_name, id, bit);
-        assert!(self.nodeid_to_index.contains_key(&id));
+        assert!(self.local_id_to_index.contains_key(&id));
         assert!(self.bits_per_id > 0);
 
-        let indices = get_cfg_indices(id, &self.nodeid_to_index);
+        let indices = get_cfg_indices(id, &self.local_id_to_index);
         for &cfgidx in indices {
             let (start, end) = self.compute_id_range(cfgidx);
             let kills = match kind {
@@ -341,15 +343,15 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
     }
 
 
-    pub fn each_bit_on_entry<F>(&self, id: ast::NodeId, mut f: F) -> bool where
+    pub fn each_bit_on_entry<F>(&self, id: hir::ItemLocalId, mut f: F) -> bool where
         F: FnMut(usize) -> bool,
     {
         //! Iterates through each bit that is set on entry to `id`.
         //! Only useful after `propagate()` has been called.
-        if !self.has_bitset_for_nodeid(id) {
+        if !self.has_bitset_for_local_id(id) {
             return true;
         }
-        let indices = get_cfg_indices(id, &self.nodeid_to_index);
+        let indices = get_cfg_indices(id, &self.local_id_to_index);
         for &cfgidx in indices {
             if !self.each_bit_for_node(EntryOrExit::Entry, cfgidx, |i| f(i)) {
                 return false;
@@ -387,11 +389,11 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
         self.each_bit(slice, f)
     }
 
-    pub fn each_gen_bit<F>(&self, id: ast::NodeId, mut f: F) -> bool where
+    pub fn each_gen_bit<F>(&self, id: hir::ItemLocalId, mut f: F) -> bool where
         F: FnMut(usize) -> bool,
     {
         //! Iterates through each bit in the gen set for `id`.
-        if !self.has_bitset_for_nodeid(id) {
+        if !self.has_bitset_for_local_id(id) {
             return true;
         }
 
@@ -401,11 +403,11 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
             return true;
         }
 
-        let indices = get_cfg_indices(id, &self.nodeid_to_index);
+        let indices = get_cfg_indices(id, &self.local_id_to_index);
         for &cfgidx in indices {
             let (start, end) = self.compute_id_range(cfgidx);
             let gens = &self.gens[start.. end];
-            debug!("{} each_gen_bit(id={}, gens={})",
+            debug!("{} each_gen_bit(id={:?}, gens={})",
                    self.analysis_name, id, bits_to_string(gens));
             if !self.each_bit(gens, |i| f(i)) {
                 return false;
@@ -472,17 +474,17 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
             let mut orig_kills = self.scope_kills[start.. end].to_vec();
 
             let mut changed = false;
-            for &node_id in &edge.data.exiting_scopes {
-                let opt_cfg_idx = self.nodeid_to_index.get(&node_id);
+            for &id in &edge.data.exiting_scopes {
+                let opt_cfg_idx = self.local_id_to_index.get(&id);
                 match opt_cfg_idx {
                     Some(indices) => {
                         for &cfg_idx in indices {
                             let (start, end) = self.compute_id_range(cfg_idx);
                             let kills = &self.scope_kills[start.. end];
                             if bitwise(&mut orig_kills, kills, &Union) {
-                                debug!("scope exits: scope id={} \
+                                debug!("scope exits: scope id={:?} \
                                         (node={:?} of {:?}) added killset: {}",
-                                       node_id, cfg_idx, indices,
+                                       id, cfg_idx, indices,
                                        bits_to_string(kills));
                                 changed = true;
                             }
@@ -490,8 +492,8 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
                     }
                     None => {
                         debug!("{} add_kills_from_flow_exits flow_exit={:?} \
-                                no cfg_idx for exiting_scope={}",
-                               self.analysis_name, flow_exit, node_id);
+                                no cfg_idx for exiting_scope={:?}",
+                               self.analysis_name, flow_exit, id);
                     }
                 }
             }
@@ -559,7 +561,7 @@ impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> {
         // Iterate over nodes in reverse postorder
         for &node_index in nodes_po.iter().rev() {
             let node = cfg.graph.node(node_index);
-            debug!("DataFlowContext::walk_cfg idx={:?} id={} begin in_out={}",
+            debug!("DataFlowContext::walk_cfg idx={:?} id={:?} begin in_out={}",
                    node_index, node.data.id(), bits_to_string(in_out));
 
             let (start, end) = self.dfcx.compute_id_range(node_index);
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index 4058f3198afb4..e83c79fb4a414 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -103,7 +103,8 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
         debug!("consume(consume_id={}, cmt={:?}, mode={:?})",
                consume_id, cmt, mode);
 
-        self.consume_common(consume_id, consume_span, cmt, mode);
+        let hir_id = self.tcx().hir.node_to_hir_id(consume_id);
+        self.consume_common(hir_id.local_id, consume_span, cmt, mode);
     }
 
     fn matched_pat(&mut self,
@@ -120,7 +121,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
                cmt,
                mode);
 
-        self.consume_common(consume_pat.id, consume_pat.span, cmt, mode);
+        self.consume_common(consume_pat.hir_id.local_id, consume_pat.span, cmt, mode);
     }
 
     fn borrow(&mut self,
@@ -136,15 +137,16 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
                borrow_id, cmt, loan_region,
                bk, loan_cause);
 
+        let hir_id = self.tcx().hir.node_to_hir_id(borrow_id);
         if let Some(lp) = opt_loan_path(&cmt) {
             let moved_value_use_kind = match loan_cause {
                 euv::ClosureCapture(_) => MovedInCapture,
                 _ => MovedInUse,
             };
-            self.check_if_path_is_moved(borrow_id, borrow_span, moved_value_use_kind, &lp);
+            self.check_if_path_is_moved(hir_id.local_id, borrow_span, moved_value_use_kind, &lp);
         }
 
-        self.check_for_conflicting_loans(borrow_id);
+        self.check_for_conflicting_loans(hir_id.local_id);
     }
 
     fn mutate(&mut self,
@@ -163,7 +165,8 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
                     // have to be *FULLY* initialized, but we still
                     // must be careful lest it contains derefs of
                     // pointers.
-                    self.check_if_assigned_path_is_moved(assignee_cmt.id,
+                    let hir_id = self.tcx().hir.node_to_hir_id(assignee_cmt.id);
+                    self.check_if_assigned_path_is_moved(hir_id.local_id,
                                                          assignment_span,
                                                          MovedInUse,
                                                          &lp);
@@ -172,14 +175,16 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
                     // In a case like `path += 1`, then path must be
                     // fully initialized, since we will read it before
                     // we write it.
-                    self.check_if_path_is_moved(assignee_cmt.id,
+                    let hir_id = self.tcx().hir.node_to_hir_id(assignee_cmt.id);
+                    self.check_if_path_is_moved(hir_id.local_id,
                                                 assignment_span,
                                                 MovedInUse,
                                                 &lp);
                 }
             }
         }
-        self.check_assignment(assignment_id, assignment_span, assignee_cmt);
+        self.check_assignment(self.tcx().hir.node_to_hir_id(assignment_id).local_id,
+                              assignment_span, assignee_cmt);
     }
 
     fn decl_without_init(&mut self, _id: ast::NodeId, _span: Span) { }
@@ -220,7 +225,7 @@ fn compatible_borrow_kinds(borrow_kind1: ty::BorrowKind,
 impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
     pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.bccx.tcx }
 
-    pub fn each_issued_loan<F>(&self, node: ast::NodeId, mut op: F) -> bool where
+    pub fn each_issued_loan<F>(&self, node: hir::ItemLocalId, mut op: F) -> bool where
         F: FnMut(&Loan<'tcx>) -> bool,
     {
         //! Iterates over each loan that has been issued
@@ -241,7 +246,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         //! Like `each_issued_loan()`, but only considers loans that are
         //! currently in scope.
 
-        self.each_issued_loan(scope.node_id(), |loan| {
+        self.each_issued_loan(self.tcx().hir.node_to_hir_id(scope.node_id()).local_id, |loan| {
             if self.bccx.region_maps.is_subscope_of(scope, loan.kill_scope) {
                 op(loan)
             } else {
@@ -325,7 +330,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         return true;
     }
 
-    pub fn loans_generated_by(&self, node: ast::NodeId) -> Vec<usize> {
+    pub fn loans_generated_by(&self, node: hir::ItemLocalId) -> Vec<usize> {
         //! Returns a vector of the loans that are generated as
         //! we enter `node`.
 
@@ -337,7 +342,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         return result;
     }
 
-    pub fn check_for_conflicting_loans(&self, node: ast::NodeId) {
+    pub fn check_for_conflicting_loans(&self, node: hir::ItemLocalId) {
         //! Checks to see whether any of the loans that are issued
         //! on entrance to `node` conflict with loans that have already been
         //! issued when we enter `node` (for example, we do not
@@ -590,7 +595,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
     }
 
     fn consume_common(&self,
-                      id: ast::NodeId,
+                      id: hir::ItemLocalId,
                       span: Span,
                       cmt: mc::cmt<'tcx>,
                       mode: euv::ConsumeMode) {
@@ -628,7 +633,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
     }
 
     fn check_for_copy_of_frozen_path(&self,
-                                     id: ast::NodeId,
+                                     id: hir::ItemLocalId,
                                      span: Span,
                                      copy_path: &LoanPath<'tcx>) {
         match self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow) {
@@ -649,7 +654,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
     }
 
     fn check_for_move_of_borrowed_path(&self,
-                                       id: ast::NodeId,
+                                       id: hir::ItemLocalId,
                                        span: Span,
                                        move_path: &LoanPath<'tcx>,
                                        move_kind: move_data::MoveKind) {
@@ -699,18 +704,21 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
     }
 
     pub fn analyze_restrictions_on_use(&self,
-                                       expr_id: ast::NodeId,
+                                       expr_id: hir::ItemLocalId,
                                        use_path: &LoanPath<'tcx>,
                                        borrow_kind: ty::BorrowKind)
                                        -> UseError<'tcx> {
-        debug!("analyze_restrictions_on_use(expr_id={}, use_path={:?})",
-               self.tcx().hir.node_to_string(expr_id),
-               use_path);
+        debug!("analyze_restrictions_on_use(expr_id={:?}, use_path={:?})",
+               expr_id, use_path);
 
         let mut ret = UseOk;
 
+        let node_id = self.tcx().hir.hir_to_node_id(hir::HirId {
+            owner: self.tcx().closure_base_def_id(self.bccx.owner_def_id).index,
+            local_id: expr_id
+        });
         self.each_in_scope_loan_affecting_path(
-            region::CodeExtent::Misc(expr_id), use_path, |loan| {
+            region::CodeExtent::Misc(node_id), use_path, |loan| {
             if !compatible_borrow_kinds(loan.kind, borrow_kind) {
                 ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span);
                 false
@@ -725,11 +733,11 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
     /// Reports an error if `expr` (which should be a path)
     /// is using a moved/uninitialized value
     fn check_if_path_is_moved(&self,
-                              id: ast::NodeId,
+                              id: hir::ItemLocalId,
                               span: Span,
                               use_kind: MovedValueUseKind,
                               lp: &Rc<LoanPath<'tcx>>) {
-        debug!("check_if_path_is_moved(id={}, use_kind={:?}, lp={:?})",
+        debug!("check_if_path_is_moved(id={:?}, use_kind={:?}, lp={:?})",
                id, use_kind, lp);
 
         // FIXME (22079): if you find yourself tempted to cut and paste
@@ -772,7 +780,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
     /// (*p).x = 22; // not ok, p is uninitialized, can't deref
     /// ```
     fn check_if_assigned_path_is_moved(&self,
-                                       id: ast::NodeId,
+                                       id: hir::ItemLocalId,
                                        span: Span,
                                        use_kind: MovedValueUseKind,
                                        lp: &Rc<LoanPath<'tcx>>)
@@ -822,14 +830,18 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
     }
 
     fn check_assignment(&self,
-                        assignment_id: ast::NodeId,
+                        assignment_id: hir::ItemLocalId,
                         assignment_span: Span,
                         assignee_cmt: mc::cmt<'tcx>) {
         debug!("check_assignment(assignee_cmt={:?})", assignee_cmt);
 
         // Check that we don't invalidate any outstanding loans
         if let Some(loan_path) = opt_loan_path(&assignee_cmt) {
-            let scope = region::CodeExtent::Misc(assignment_id);
+            let node_id = self.tcx().hir.hir_to_node_id(hir::HirId {
+                owner: self.tcx().closure_base_def_id(self.bccx.owner_def_id).index,
+                local_id: assignment_id
+            });
+            let scope = region::CodeExtent::Misc(node_id);
             self.each_in_scope_loan_affecting_path(scope, &loan_path, |loan| {
                 self.report_illegal_mutation(assignment_span, &loan_path, loan);
                 false
diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
index 7878762788905..465457f5ab39a 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
@@ -27,7 +27,7 @@ use rustc::hir::*;
 use rustc::hir::map::Node::*;
 
 struct GatherMoveInfo<'tcx> {
-    id: ast::NodeId,
+    id: hir::ItemLocalId,
     kind: MoveKind,
     cmt: mc::cmt<'tcx>,
     span_path_opt: Option<MovePlace<'tcx>>
@@ -79,13 +79,14 @@ pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                              var_id: ast::NodeId,
                              var_ty: Ty<'tcx>) {
     let loan_path = Rc::new(LoanPath::new(LpVar(var_id), var_ty));
-    move_data.add_move(bccx.tcx, loan_path, var_id, Declared);
+    let hir_id = bccx.tcx.hir.node_to_hir_id(var_id);
+    move_data.add_move(bccx.tcx, loan_path, hir_id.local_id, Declared);
 }
 
 pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                        move_data: &MoveData<'tcx>,
                                        move_error_collector: &mut MoveErrorCollector<'tcx>,
-                                       move_expr_id: ast::NodeId,
+                                       move_expr_id: hir::ItemLocalId,
                                        cmt: mc::cmt<'tcx>,
                                        move_reason: euv::MoveReason) {
     let kind = match move_reason {
@@ -118,7 +119,7 @@ pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         _ => None,
     };
     let move_info = GatherMoveInfo {
-        id: move_pat.id,
+        id: move_pat.hir_id.local_id,
         kind: MovePat,
         cmt,
         span_path_opt: pat_span_path_opt,
@@ -135,7 +136,7 @@ fn gather_move<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                          move_data: &MoveData<'tcx>,
                          move_error_collector: &mut MoveErrorCollector<'tcx>,
                          move_info: GatherMoveInfo<'tcx>) {
-    debug!("gather_move(move_id={}, cmt={:?})",
+    debug!("gather_move(move_id={:?}, cmt={:?})",
            move_info.id, move_info.cmt);
 
     let potentially_illegal_move =
@@ -161,10 +162,10 @@ fn gather_move<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
 
 pub fn gather_assignment<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                    move_data: &MoveData<'tcx>,
-                                   assignment_id: ast::NodeId,
+                                   assignment_id: hir::ItemLocalId,
                                    assignment_span: Span,
                                    assignee_loan_path: Rc<LoanPath<'tcx>>,
-                                   assignee_id: ast::NodeId,
+                                   assignee_id: hir::ItemLocalId,
                                    mode: euv::MutateMode) {
     move_data.add_assignment(bccx.tcx,
                              assignee_loan_path,
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index 68bffb90f4da8..e14edc43904ea 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -44,7 +44,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         bccx,
         all_loans: Vec::new(),
         item_ub: region::CodeExtent::Misc(body.node_id),
-        move_data: MoveData::new(),
+        move_data: MoveData::default(),
         move_error_collector: move_error::MoveErrorCollector::new(),
     };
 
@@ -79,7 +79,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
             euv::Move(move_reason) => {
                 gather_moves::gather_move_from_expr(
                     self.bccx, &self.move_data, &mut self.move_error_collector,
-                    consume_id, cmt, move_reason);
+                    self.bccx.tcx.hir.node_to_hir_id(consume_id).local_id, cmt, move_reason);
             }
             euv::Copy => { }
         }
@@ -272,8 +272,12 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
                     self.mark_loan_path_as_mutated(&lp);
                 }
                 gather_moves::gather_assignment(self.bccx, &self.move_data,
-                                                assignment_id, assignment_span,
-                                                lp, cmt.id, mode);
+                                                self.bccx.tcx.hir.node_to_hir_id(assignment_id)
+                                                    .local_id,
+                                                assignment_span,
+                                                lp,
+                                                self.bccx.tcx.hir.node_to_hir_id(cmt.id).local_id,
+                                                mode);
             }
             None => {
                 // This can occur with e.g. `*foo() = 5`.  In such
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index eca713a98df57..0b62da306db47 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -167,9 +167,11 @@ fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>(this: &mut BorrowckCtxt<'a, 'tc
                              id_range,
                              all_loans.len());
     for (loan_idx, loan) in all_loans.iter().enumerate() {
-        loan_dfcx.add_gen(loan.gen_scope.node_id(), loan_idx);
+        loan_dfcx.add_gen(this.tcx.hir.node_to_hir_id(loan.gen_scope.node_id()).local_id,
+                          loan_idx);
         loan_dfcx.add_kill(KillFrom::ScopeEnd,
-                           loan.kill_scope.node_id(), loan_idx);
+                           this.tcx.hir.node_to_hir_id(loan.kill_scope.node_id()).local_id,
+                           loan_idx);
     }
     loan_dfcx.add_kills_from_flow_exits(cfg);
     loan_dfcx.propagate(cfg, this.body);
@@ -640,19 +642,22 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
 
         // Get type of value and span where it was previously
         // moved.
+        let node_id = self.tcx.hir.hir_to_node_id(hir::HirId {
+            owner: self.tcx.closure_base_def_id(self.owner_def_id).index,
+            local_id: the_move.id
+        });
         let (move_span, move_note) = match the_move.kind {
             move_data::Declared => {
                 unreachable!();
             }
 
             move_data::MoveExpr |
-            move_data::MovePat =>
-                (self.tcx.hir.span(the_move.id), ""),
+            move_data::MovePat => (self.tcx.hir.span(node_id), ""),
 
             move_data::Captured =>
-                (match self.tcx.hir.expect_expr(the_move.id).node {
+                (match self.tcx.hir.expect_expr(node_id).node {
                     hir::ExprClosure(.., fn_decl_span, _) => fn_decl_span,
-                    ref r => bug!("Captured({}) maps to non-closure: {:?}",
+                    ref r => bug!("Captured({:?}) maps to non-closure: {:?}",
                                   the_move.id, r),
                 }, " (into closure)"),
         };
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index 217bd6e6ca1ca..79a4a4f9f4d5b 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -23,16 +23,16 @@ use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::expr_use_visitor::MutateMode;
 use rustc::middle::mem_categorization as mc;
 use rustc::ty::{self, TyCtxt};
-use rustc::util::nodemap::{FxHashMap, NodeSet};
+use rustc::util::nodemap::{FxHashMap, FxHashSet};
 
 use std::cell::RefCell;
 use std::rc::Rc;
 use std::usize;
-use syntax::ast;
 use syntax_pos::Span;
 use rustc::hir;
 use rustc::hir::intravisit::IdRange;
 
+#[derive(Default)]
 pub struct MoveData<'tcx> {
     /// Move paths. See section "Move paths" in `README.md`.
     pub paths: RefCell<Vec<MovePath<'tcx>>>,
@@ -54,7 +54,7 @@ pub struct MoveData<'tcx> {
     pub path_assignments: RefCell<Vec<Assignment>>,
 
     /// Assignments to a variable or path, like `x = foo`, but not `x += foo`.
-    pub assignee_ids: RefCell<NodeSet>,
+    pub assignee_ids: RefCell<FxHashSet<hir::ItemLocalId>>,
 }
 
 pub struct FlowedMoveData<'a, 'tcx: 'a> {
@@ -133,7 +133,7 @@ pub struct Move {
     pub path: MovePathIndex,
 
     /// id of node that is doing the move.
-    pub id: ast::NodeId,
+    pub id: hir::ItemLocalId,
 
     /// Kind of move, for error messages.
     pub kind: MoveKind,
@@ -148,13 +148,13 @@ pub struct Assignment {
     pub path: MovePathIndex,
 
     /// id where assignment occurs
-    pub id: ast::NodeId,
+    pub id: hir::ItemLocalId,
 
     /// span of node where assignment occurs
     pub span: Span,
 
     /// id for l-value expression on lhs of assignment
-    pub assignee_id: ast::NodeId,
+    pub assignee_id: hir::ItemLocalId,
 }
 
 #[derive(Clone, Copy)]
@@ -189,17 +189,6 @@ fn loan_path_is_precise(loan_path: &LoanPath) -> bool {
 }
 
 impl<'a, 'tcx> MoveData<'tcx> {
-    pub fn new() -> MoveData<'tcx> {
-        MoveData {
-            paths: RefCell::new(Vec::new()),
-            path_map: RefCell::new(FxHashMap()),
-            moves: RefCell::new(Vec::new()),
-            path_assignments: RefCell::new(Vec::new()),
-            var_assignments: RefCell::new(Vec::new()),
-            assignee_ids: RefCell::new(NodeSet()),
-        }
-    }
-
     /// return true if there are no trackable assignments or moves
     /// in this move data - that means that there is nothing that
     /// could cause a borrow error.
@@ -345,7 +334,7 @@ impl<'a, 'tcx> MoveData<'tcx> {
     /// Adds a new move entry for a move of `lp` that occurs at location `id` with kind `kind`.
     pub fn add_move(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     orig_lp: Rc<LoanPath<'tcx>>,
-                    id: ast::NodeId,
+                    id: hir::ItemLocalId,
                     kind: MoveKind) {
         // Moving one union field automatically moves all its fields. Also move siblings of
         // all parent union fields, moves do not propagate upwards automatically.
@@ -373,9 +362,9 @@ impl<'a, 'tcx> MoveData<'tcx> {
 
     fn add_move_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                        lp: Rc<LoanPath<'tcx>>,
-                       id: ast::NodeId,
+                       id: hir::ItemLocalId,
                        kind: MoveKind) {
-        debug!("add_move(lp={:?}, id={}, kind={:?})",
+        debug!("add_move(lp={:?}, id={:?}, kind={:?})",
                lp,
                id,
                kind);
@@ -398,9 +387,9 @@ impl<'a, 'tcx> MoveData<'tcx> {
     /// `span`.
     pub fn add_assignment(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           lp: Rc<LoanPath<'tcx>>,
-                          assign_id: ast::NodeId,
+                          assign_id: hir::ItemLocalId,
                           span: Span,
-                          assignee_id: ast::NodeId,
+                          assignee_id: hir::ItemLocalId,
                           mode: euv::MutateMode) {
         // Assigning to one union field automatically assigns to all its fields.
         if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind {
@@ -429,11 +418,11 @@ impl<'a, 'tcx> MoveData<'tcx> {
 
     fn add_assignment_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              lp: Rc<LoanPath<'tcx>>,
-                             assign_id: ast::NodeId,
+                             assign_id: hir::ItemLocalId,
                              span: Span,
-                             assignee_id: ast::NodeId,
+                             assignee_id: hir::ItemLocalId,
                              mode: euv::MutateMode) {
-        debug!("add_assignment(lp={:?}, assign_id={}, assignee_id={}",
+        debug!("add_assignment(lp={:?}, assign_id={:?}, assignee_id={:?}",
                lp, assign_id, assignee_id);
 
         let path_index = self.move_path(tcx, lp.clone());
@@ -496,7 +485,8 @@ impl<'a, 'tcx> MoveData<'tcx> {
                 LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
                     let kill_scope = path.loan_path.kill_scope(bccx);
                     let path = *self.path_map.borrow().get(&path.loan_path).unwrap();
-                    self.kill_moves(path, kill_scope.node_id(),
+                    self.kill_moves(path,
+                                    bccx.tcx.hir.node_to_hir_id(kill_scope.node_id()).local_id,
                                     KillFrom::ScopeEnd, dfcx_moves);
                 }
                 LpExtend(..) => {}
@@ -511,7 +501,8 @@ impl<'a, 'tcx> MoveData<'tcx> {
                 LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
                     let kill_scope = lp.kill_scope(bccx);
                     dfcx_assign.add_kill(KillFrom::ScopeEnd,
-                                         kill_scope.node_id(),
+                                         bccx.tcx.hir.node_to_hir_id(kill_scope.node_id())
+                                            .local_id,
                                          assignment_index);
                 }
                 LpExtend(..) => {
@@ -579,7 +570,7 @@ impl<'a, 'tcx> MoveData<'tcx> {
 
     fn kill_moves(&self,
                   path: MovePathIndex,
-                  kill_id: ast::NodeId,
+                  kill_id: hir::ItemLocalId,
                   kill_kind: KillFrom,
                   dfcx_moves: &mut MoveDataFlow) {
         // We can only perform kills for paths that refer to a unique location,
@@ -589,7 +580,7 @@ impl<'a, 'tcx> MoveData<'tcx> {
         let loan_path = self.path_loan_path(path);
         if loan_path_is_precise(&loan_path) {
             self.each_applicable_move(path, |move_index| {
-                debug!("kill_moves add_kill {:?} kill_id={} move_index={}",
+                debug!("kill_moves add_kill {:?} kill_id={:?} move_index={}",
                        kill_kind, kill_id, move_index.get());
                 dfcx_moves.add_kill(kill_kind, kill_id, move_index.get());
                 true
@@ -642,7 +633,7 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
     }
 
     pub fn kind_of_move_of_path(&self,
-                                id: ast::NodeId,
+                                id: hir::ItemLocalId,
                                 loan_path: &Rc<LoanPath<'tcx>>)
                                 -> Option<MoveKind> {
         //! Returns the kind of a move of `loan_path` by `id`, if one exists.
@@ -667,7 +658,7 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
     /// have occurred on entry to `id` without an intervening assignment. In other words, any moves
     /// that would invalidate a reference to `loan_path` at location `id`.
     pub fn each_move_of<F>(&self,
-                           id: ast::NodeId,
+                           id: hir::ItemLocalId,
                            loan_path: &Rc<LoanPath<'tcx>>,
                            mut f: F)
                            -> bool where
@@ -724,7 +715,7 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
     /// Iterates through every assignment to `loan_path` that may have occurred on entry to `id`.
     /// `loan_path` must be a single variable.
     pub fn each_assignment_of<F>(&self,
-                                 id: ast::NodeId,
+                                 id: hir::ItemLocalId,
                                  loan_path: &Rc<LoanPath<'tcx>>,
                                  mut f: F)
                                  -> bool where
diff --git a/src/librustc_borrowck/graphviz.rs b/src/librustc_borrowck/graphviz.rs
index e3a2bfa392738..22867ba5b55a4 100644
--- a/src/librustc_borrowck/graphviz.rs
+++ b/src/librustc_borrowck/graphviz.rs
@@ -52,7 +52,7 @@ pub struct DataflowLabeller<'a, 'tcx: 'a> {
 impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> {
     fn dataflow_for(&self, e: EntryOrExit, n: &Node<'a>) -> String {
         let id = n.1.data.id();
-        debug!("dataflow_for({:?}, id={}) {:?}", e, id, self.variants);
+        debug!("dataflow_for({:?}, id={:?}) {:?}", e, id, self.variants);
         let mut sets = "".to_string();
         let mut seen_one = false;
         for &variant in &self.variants {
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 20f2a146b0b15..6a58b7fb75360 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -765,7 +765,7 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
     let cfg = cfg::CFG::new(tcx, &body);
     let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
     let lcfg = LabelledCFG {
-        hir_map: &tcx.hir,
+        tcx,
         cfg: &cfg,
         name: format!("node_{}", code.id()),
         labelled_edges,
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 3bfe2897de175..0fe30dcabb00d 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -850,23 +850,25 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
             }
             visited.insert(cfg_id);
 
-            let node_id = cfg.graph.node_data(idx).id();
-
             // is this a recursive call?
-            let self_recursive = if node_id != ast::DUMMY_NODE_ID {
-                match method {
+            let local_id = cfg.graph.node_data(idx).id();
+            if local_id != hir::DUMMY_ITEM_LOCAL_ID {
+                let node_id = cx.tcx.hir.hir_to_node_id(hir::HirId {
+                    owner: cx.tcx.closure_base_def_id(cfg.owner_def_id).index,
+                    local_id
+                });
+                let self_recursive = match method {
                     Some(ref method) => expr_refers_to_this_method(cx, method, node_id),
                     None => expr_refers_to_this_fn(cx, id, node_id),
+                };
+                if self_recursive {
+                    self_call_spans.push(cx.tcx.hir.span(node_id));
+                    // this is a self call, so we shouldn't explore past
+                    // this node in the CFG.
+                    continue;
                 }
-            } else {
-                false
-            };
-            if self_recursive {
-                self_call_spans.push(cx.tcx.hir.span(node_id));
-                // this is a self call, so we shouldn't explore past
-                // this node in the CFG.
-                continue;
             }
+
             // add the successors of this node to explore the graph further.
             for (_, edge) in cfg.graph.outgoing_edges(idx) {
                 let target_idx = edge.target();

From ea6aca7726bd035ae79fc4643f863178c8f26e90 Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Wed, 30 Aug 2017 02:39:06 +0300
Subject: [PATCH 2/3] rustc: take TyCtxt and RegionMaps in CodeMap::span.

---
 src/librustc/infer/error_reporting/mod.rs     |  31 +++--
 src/librustc/infer/error_reporting/note.rs    | 112 ++++++++++--------
 src/librustc/infer/mod.rs                     |   2 +-
 src/librustc/middle/region.rs                 |  48 ++++----
 src/librustc/ty/error.rs                      |  37 +-----
 src/librustc/ty/structural_impls.rs           |  16 +--
 src/librustc_borrowck/borrowck/mod.rs         |  13 +-
 src/librustc_mir/build/block.rs               |   8 +-
 src/librustc_mir/build/scope.rs               |   3 +-
 src/librustc_mir/hair/cx/block.rs             |   2 -
 src/librustc_mir/hair/mod.rs                  |   1 -
 .../check/generator_interior.rs               |  16 +--
 .../mismatched_types/closure-mismatch.stderr  |   1 -
 13 files changed, 120 insertions(+), 170 deletions(-)

diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 4c55c1474a326..d86626c210e14 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -64,7 +64,7 @@ use std::fmt;
 use hir;
 use hir::map as hir_map;
 use hir::def_id::DefId;
-use middle::region;
+use middle::region::{self, RegionMaps};
 use traits::{ObligationCause, ObligationCauseCode};
 use ty::{self, Region, TyCtxt, TypeFoldable};
 use ty::error::TypeError;
@@ -83,6 +83,7 @@ mod anon_anon_conflict;
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn note_and_explain_region(self,
+                                   region_maps: &RegionMaps,
                                    err: &mut DiagnosticBuilder,
                                    prefix: &str,
                                    region: ty::Region<'tcx>,
@@ -130,13 +131,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     format!("{}unknown scope: {:?}{}.  Please report a bug.",
                             prefix, scope, suffix)
                 };
-                let span = match scope.span(&self.hir) {
-                    Some(s) => s,
-                    None => {
-                        err.note(&unknown_scope());
-                        return;
-                    }
-                };
+                let span = scope.span(self, region_maps);
                 let tag = match self.hir.find(scope.node_id()) {
                     Some(hir_map::NodeBlock(_)) => "block",
                     Some(hir_map::NodeExpr(expr)) => match expr.node {
@@ -260,8 +255,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-
-    pub fn report_region_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>) {
+    pub fn report_region_errors(&self,
+                                region_maps: &RegionMaps,
+                                errors: &Vec<RegionResolutionError<'tcx>>) {
         debug!("report_region_errors(): {} errors to start", errors.len());
 
         // try to pre-process the errors, which will group some of them
@@ -285,16 +281,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                   // the error. If all of these fails, we fall back to a rather
                   // general bit of code that displays the error information
                   ConcreteFailure(origin, sub, sup) => {
-
-                      self.report_concrete_failure(origin, sub, sup).emit();
+                      self.report_concrete_failure(region_maps, origin, sub, sup).emit();
                   }
 
                   GenericBoundFailure(kind, param_ty, sub) => {
-                      self.report_generic_bound_failure(kind, param_ty, sub);
+                      self.report_generic_bound_failure(region_maps, kind, param_ty, sub);
                   }
 
                   SubSupConflict(var_origin, sub_origin, sub_r, sup_origin, sup_r) => {
-                        self.report_sub_sup_conflict(var_origin,
+                        self.report_sub_sup_conflict(region_maps,
+                                                     var_origin,
                                                      sub_origin,
                                                      sub_r,
                                                      sup_origin,
@@ -773,6 +769,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn report_generic_bound_failure(&self,
+                                    region_maps: &RegionMaps,
                                     origin: SubregionOrigin<'tcx>,
                                     bound_kind: GenericKind<'tcx>,
                                     sub: Region<'tcx>)
@@ -840,6 +837,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 err.help(&format!("consider adding an explicit lifetime bound for `{}`",
                                   bound_kind));
                 self.tcx.note_and_explain_region(
+                    region_maps,
                     &mut err,
                     &format!("{} must be valid for ", labeled_user_string),
                     sub,
@@ -853,6 +851,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn report_sub_sup_conflict(&self,
+                               region_maps: &RegionMaps,
                                var_origin: RegionVariableOrigin,
                                sub_origin: SubregionOrigin<'tcx>,
                                sub_region: Region<'tcx>,
@@ -860,14 +859,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                sup_region: Region<'tcx>) {
         let mut err = self.report_inference_failure(var_origin);
 
-        self.tcx.note_and_explain_region(&mut err,
+        self.tcx.note_and_explain_region(region_maps, &mut err,
             "first, the lifetime cannot outlive ",
             sup_region,
             "...");
 
         self.note_region_origin(&mut err, &sup_origin);
 
-        self.tcx.note_and_explain_region(&mut err,
+        self.tcx.note_and_explain_region(region_maps, &mut err,
             "but, the lifetime must be valid for ",
             sub_region,
             "...");
diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs
index 87047d0df144c..3e78cce80f594 100644
--- a/src/librustc/infer/error_reporting/note.rs
+++ b/src/librustc/infer/error_reporting/note.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use infer::{self, InferCtxt, SubregionOrigin};
+use middle::region::RegionMaps;
 use ty::{self, Region};
 use ty::error::TypeError;
 use errors::DiagnosticBuilder;
@@ -144,6 +145,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub(super) fn report_concrete_failure(&self,
+                                          region_maps: &RegionMaps,
                                           origin: SubregionOrigin<'tcx>,
                                           sub: Region<'tcx>,
                                           sup: Region<'tcx>)
@@ -151,7 +153,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         match origin {
             infer::Subtype(trace) => {
                 let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
-                self.report_and_explain_type_error(trace, &terr)
+                let mut err = self.report_and_explain_type_error(trace, &terr);
+                self.tcx.note_and_explain_region(region_maps, &mut err, "", sup, "...");
+                self.tcx.note_and_explain_region(region_maps, &mut err,
+                    "...does not necessarily outlive ", sub, "");
+                err
             }
             infer::Reborrow(span) => {
                 let mut err = struct_span_err!(self.tcx.sess,
@@ -159,11 +165,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                E0312,
                                                "lifetime of reference outlives lifetime of \
                                                 borrowed content...");
-                self.tcx.note_and_explain_region(&mut err,
+                self.tcx.note_and_explain_region(region_maps, &mut err,
                                                  "...the reference is valid for ",
                                                  sub,
                                                  "...");
-                self.tcx.note_and_explain_region(&mut err,
+                self.tcx.note_and_explain_region(region_maps, &mut err,
                                                  "...but the borrowed content is only valid for ",
                                                  sup,
                                                  "");
@@ -177,27 +183,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                 of captured variable `{}`...",
                                                self.tcx
                                                    .local_var_name_str_def_index(upvar_id.var_id));
-                self.tcx.note_and_explain_region(&mut err,
+                self.tcx.note_and_explain_region(region_maps, &mut err,
                                                  "...the borrowed pointer is valid for ",
                                                  sub,
                                                  "...");
-                self.tcx
-                    .note_and_explain_region(
-                      &mut err,
-                      &format!("...but `{}` is only valid for ",
-                               self.tcx.local_var_name_str_def_index(upvar_id.var_id)),
-                      sup,
-                      "");
+                self.tcx.note_and_explain_region(
+                    region_maps,
+                    &mut err,
+                    &format!("...but `{}` is only valid for ",
+                        self.tcx.local_var_name_str_def_index(upvar_id.var_id)),
+                    sup,
+                    "");
                 err
             }
             infer::InfStackClosure(span) => {
                 let mut err =
                     struct_span_err!(self.tcx.sess, span, E0314, "closure outlives stack frame");
-                self.tcx.note_and_explain_region(&mut err,
+                self.tcx.note_and_explain_region(region_maps, &mut err,
                                                  "...the closure must be valid for ",
                                                  sub,
                                                  "...");
-                self.tcx.note_and_explain_region(&mut err,
+                self.tcx.note_and_explain_region(region_maps, &mut err,
                                                  "...but the closure's stack frame is only valid \
                                                   for ",
                                                  sup,
@@ -209,8 +215,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                span,
                                                E0315,
                                                "cannot invoke closure outside of its lifetime");
-                self.tcx
-                    .note_and_explain_region(&mut err, "the closure is only valid for ", sup, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err,
+                    "the closure is only valid for ", sup, "");
                 err
             }
             infer::DerefPointer(span) => {
@@ -218,8 +224,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                span,
                                                E0473,
                                                "dereference of reference outside its lifetime");
-                self.tcx
-                    .note_and_explain_region(&mut err, "the reference is only valid for ", sup, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err,
+                    "the reference is only valid for ", sup, "");
                 err
             }
             infer::FreeVariable(span, id) => {
@@ -229,9 +235,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                "captured variable `{}` does not outlive the \
                                                 enclosing closure",
                                                self.tcx.local_var_name_str(id));
-                self.tcx
-                    .note_and_explain_region(&mut err, "captured variable is valid for ", sup, "");
-                self.tcx.note_and_explain_region(&mut err, "closure is valid for ", sub, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err,
+                    "captured variable is valid for ", sup, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err,
+                    "closure is valid for ", sub, "");
                 err
             }
             infer::IndexSlice(span) => {
@@ -239,7 +246,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                span,
                                                E0475,
                                                "index of slice outside its lifetime");
-                self.tcx.note_and_explain_region(&mut err, "the slice is only valid for ", sup, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err,
+                    "the slice is only valid for ", sup, "");
                 err
             }
             infer::RelateObjectBound(span) => {
@@ -248,8 +256,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                E0476,
                                                "lifetime of the source pointer does not outlive \
                                                 lifetime bound of the object type");
-                self.tcx.note_and_explain_region(&mut err, "object type is valid for ", sub, "");
-                self.tcx.note_and_explain_region(&mut err,
+                self.tcx.note_and_explain_region(region_maps, &mut err,
+                    "object type is valid for ", sub, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err,
                                                  "source pointer is only valid for ",
                                                  sup,
                                                  "");
@@ -264,10 +273,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                self.ty_to_string(ty));
                 match *sub {
                     ty::ReStatic => {
-                        self.tcx.note_and_explain_region(&mut err, "type must satisfy ", sub, "")
+                        self.tcx.note_and_explain_region(region_maps, &mut err,
+                            "type must satisfy ", sub, "")
                     }
                     _ => {
-                        self.tcx.note_and_explain_region(&mut err, "type must outlive ", sub, "")
+                        self.tcx.note_and_explain_region(region_maps, &mut err,
+                            "type must outlive ", sub, "")
                     }
                 }
                 err
@@ -275,11 +286,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             infer::RelateRegionParamBound(span) => {
                 let mut err =
                     struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
-                self.tcx.note_and_explain_region(&mut err,
+                self.tcx.note_and_explain_region(region_maps, &mut err,
                                                  "lifetime parameter instantiated with ",
                                                  sup,
                                                  "");
-                self.tcx.note_and_explain_region(&mut err,
+                self.tcx.note_and_explain_region(region_maps, &mut err,
                                                  "but lifetime parameter must outlive ",
                                                  sub,
                                                  "");
@@ -292,7 +303,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                "the type `{}` (provided as the value of a type \
                                                 parameter) is not valid at this point",
                                                self.ty_to_string(ty));
-                self.tcx.note_and_explain_region(&mut err, "type must outlive ", sub, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err,
+                    "type must outlive ", sub, "");
                 err
             }
             infer::CallRcvr(span) => {
@@ -301,8 +313,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                E0480,
                                                "lifetime of method receiver does not outlive the \
                                                 method call");
-                self.tcx
-                    .note_and_explain_region(&mut err, "the receiver is only valid for ", sup, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err,
+                "the receiver is only valid for ", sup, "");
                 err
             }
             infer::CallArg(span) => {
@@ -311,7 +323,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                E0481,
                                                "lifetime of function argument does not outlive \
                                                 the function call");
-                self.tcx.note_and_explain_region(&mut err,
+                self.tcx.note_and_explain_region(region_maps, &mut err,
                                                  "the function argument is only valid for ",
                                                  sup,
                                                  "");
@@ -323,7 +335,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                E0482,
                                                "lifetime of return value does not outlive the \
                                                 function call");
-                self.tcx.note_and_explain_region(&mut err,
+                self.tcx.note_and_explain_region(region_maps, &mut err,
                                                  "the return value is only valid for ",
                                                  sup,
                                                  "");
@@ -335,8 +347,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                E0483,
                                                "lifetime of operand does not outlive the \
                                                 operation");
-                self.tcx
-                    .note_and_explain_region(&mut err, "the operand is only valid for ", sup, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err,
+                    "the operand is only valid for ", sup, "");
                 err
             }
             infer::AddrOf(span) => {
@@ -344,8 +356,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                span,
                                                E0484,
                                                "reference is not valid at the time of borrow");
-                self.tcx
-                    .note_and_explain_region(&mut err, "the borrow is only valid for ", sup, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err,
+                    "the borrow is only valid for ", sup, "");
                 err
             }
             infer::AutoBorrow(span) => {
@@ -354,7 +366,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                E0485,
                                                "automatically reference is not valid at the time \
                                                 of borrow");
-                self.tcx.note_and_explain_region(&mut err,
+                self.tcx.note_and_explain_region(region_maps, &mut err,
                                                  "the automatic borrow is only valid for ",
                                                  sup,
                                                  "");
@@ -367,7 +379,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                "type of expression contains references that are \
                                                 not valid during the expression: `{}`",
                                                self.ty_to_string(t));
-                self.tcx.note_and_explain_region(&mut err, "type is only valid for ", sup, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err,
+                    "type is only valid for ", sup, "");
                 err
             }
             infer::SafeDestructor(span) => {
@@ -377,8 +390,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                "unsafe use of destructor: destructor might be \
                                                 called while references are dead");
                 // FIXME (22171): terms "super/subregion" are suboptimal
-                self.tcx.note_and_explain_region(&mut err, "superregion: ", sup, "");
-                self.tcx.note_and_explain_region(&mut err, "subregion: ", sub, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err, "superregion: ", sup, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err, "subregion: ", sub, "");
                 err
             }
             infer::BindingTypeIsNotValidAtDecl(span) => {
@@ -387,8 +400,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                E0488,
                                                "lifetime of variable does not enclose its \
                                                 declaration");
-                self.tcx
-                    .note_and_explain_region(&mut err, "the variable is only valid for ", sup, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err,
+                    "the variable is only valid for ", sup, "");
                 err
             }
             infer::ParameterInScope(_, span) => {
@@ -396,8 +409,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                span,
                                                E0489,
                                                "type/lifetime parameter not in scope here");
-                self.tcx
-                    .note_and_explain_region(&mut err, "the parameter is only valid for ", sub, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err,
+                    "the parameter is only valid for ", sub, "");
                 err
             }
             infer::DataBorrowed(ty, span) => {
@@ -406,8 +419,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                E0490,
                                                "a value of type `{}` is borrowed for too long",
                                                self.ty_to_string(ty));
-                self.tcx.note_and_explain_region(&mut err, "the type is valid for ", sub, "");
-                self.tcx.note_and_explain_region(&mut err, "but the borrow lasts for ", sup, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err,
+                    "the type is valid for ", sub, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err,
+                    "but the borrow lasts for ", sup, "");
                 err
             }
             infer::ReferenceOutlivesReferent(ty, span) => {
@@ -417,8 +432,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                                "in type `{}`, reference has a longer lifetime \
                                                 than the data it references",
                                                self.ty_to_string(ty));
-                self.tcx.note_and_explain_region(&mut err, "the pointer is valid for ", sub, "");
-                self.tcx.note_and_explain_region(&mut err,
+                self.tcx.note_and_explain_region(region_maps, &mut err,
+                    "the pointer is valid for ", sub, "");
+                self.tcx.note_and_explain_region(region_maps, &mut err,
                                                  "but the referenced data is only valid for ",
                                                  sup,
                                                  "");
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 27c6a4c5cf291..21af92a25e684 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1084,7 +1084,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             // this infcx was in use.  This is totally hokey but
             // otherwise we have a hard time separating legit region
             // errors from silly ones.
-            self.report_region_errors(&errors); // see error_reporting module
+            self.report_region_errors(region_map, &errors); // see error_reporting module
         }
     }
 
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 8b01d5045c6b0..10a21a582f554 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -16,7 +16,6 @@
 //! Most of the documentation on regions can be found in
 //! `middle/infer/region_inference/README.md`
 
-use hir::map as hir_map;
 use util::nodemap::{FxHashMap, NodeMap, NodeSet};
 use ty;
 
@@ -161,34 +160,31 @@ impl CodeExtent {
     /// Returns the span of this CodeExtent.  Note that in general the
     /// returned span may not correspond to the span of any node id in
     /// the AST.
-    pub fn span(&self, hir_map: &hir_map::Map) -> Option<Span> {
-        match hir_map.find(self.node_id()) {
-            Some(hir_map::NodeBlock(ref blk)) => {
-                match *self {
-                    CodeExtent::CallSiteScope(_) |
-                    CodeExtent::ParameterScope(_) |
-                    CodeExtent::Misc(_) |
-                    CodeExtent::DestructionScope(_) => Some(blk.span),
-
-                    CodeExtent::Remainder(r) => {
-                        assert_eq!(r.block, blk.id);
-                        // Want span for extent starting after the
-                        // indexed statement and ending at end of
-                        // `blk`; reuse span of `blk` and shift `lo`
-                        // forward to end of indexed statement.
-                        //
-                        // (This is the special case aluded to in the
-                        // doc-comment for this method)
-                        let stmt_span = blk.stmts[r.first_statement_index as usize].span;
-                        Some(Span::new(stmt_span.hi(), blk.span.hi(), stmt_span.ctxt()))
-                    }
+    pub fn span(&self, tcx: TyCtxt, region_maps: &RegionMaps) -> Span {
+        let root_node = region_maps.root_body.unwrap().node_id;
+        assert_eq!(DefId::local(tcx.hir.node_to_hir_id(self.node_id()).owner),
+                   DefId::local(tcx.hir.node_to_hir_id(root_node).owner));
+        let span = tcx.hir.span(self.node_id());
+        if let CodeExtent::Remainder(r) = *self {
+            if let hir::map::NodeBlock(ref blk) = tcx.hir.get(r.block) {
+                // Want span for extent starting after the
+                // indexed statement and ending at end of
+                // `blk`; reuse span of `blk` and shift `lo`
+                // forward to end of indexed statement.
+                //
+                // (This is the special case aluded to in the
+                // doc-comment for this method)
+
+                let stmt_span = blk.stmts[r.first_statement_index as usize].span;
+
+                // To avoid issues with macro-generated spans, the span
+                // of the statement must be nested in that of the block.
+                if span.lo() <= stmt_span.lo() && stmt_span.lo() <= span.hi() {
+                    return Span::new(stmt_span.lo(), span.hi(), span.ctxt());
                 }
             }
-            Some(hir_map::NodeExpr(ref expr)) => Some(expr.span),
-            Some(hir_map::NodeStmt(ref stmt)) => Some(stmt.span),
-            Some(hir_map::NodeItem(ref item)) => Some(item.span),
-            Some(_) | None => None,
          }
+         span
     }
 }
 
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 802994ae0948a..49d7f40000f07 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -36,11 +36,11 @@ pub enum TypeError<'tcx> {
     TupleSize(ExpectedFound<usize>),
     FixedArraySize(ExpectedFound<usize>),
     ArgCount,
+
     RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
-    RegionsNotSame(Region<'tcx>, Region<'tcx>),
-    RegionsNoOverlap(Region<'tcx>, Region<'tcx>),
     RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>),
     RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>),
+
     Sorts(ExpectedFound<Ty<'tcx>>),
     IntMismatch(ExpectedFound<ty::IntVarValue>),
     FloatMismatch(ExpectedFound<ast::FloatTy>),
@@ -110,12 +110,6 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
             RegionsDoesNotOutlive(..) => {
                 write!(f, "lifetime mismatch")
             }
-            RegionsNotSame(..) => {
-                write!(f, "lifetimes are not the same")
-            }
-            RegionsNoOverlap(..) => {
-                write!(f, "lifetimes do not intersect")
-            }
             RegionsInsufficientlyPolymorphic(br, _) => {
                 write!(f,
                        "expected bound lifetime parameter{}{}, found concrete lifetime",
@@ -243,33 +237,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         use self::TypeError::*;
 
         match err.clone() {
-            RegionsDoesNotOutlive(subregion, superregion) => {
-                self.note_and_explain_region(db, "", subregion, "...");
-                self.note_and_explain_region(db, "...does not necessarily outlive ",
-                                           superregion, "");
-            }
-            RegionsNotSame(region1, region2) => {
-                self.note_and_explain_region(db, "", region1, "...");
-                self.note_and_explain_region(db, "...is not the same lifetime as ",
-                                           region2, "");
-            }
-            RegionsNoOverlap(region1, region2) => {
-                self.note_and_explain_region(db, "", region1, "...");
-                self.note_and_explain_region(db, "...does not overlap ",
-                                           region2, "");
-            }
-            RegionsInsufficientlyPolymorphic(_, conc_region) => {
-                self.note_and_explain_region(db, "concrete lifetime that was found is ",
-                                           conc_region, "");
-            }
-            RegionsOverlyPolymorphic(_, &ty::ReVar(_)) => {
-                // don't bother to print out the message below for
-                // inference variables, it's not very illuminating.
-            }
-            RegionsOverlyPolymorphic(_, conc_region) => {
-                self.note_and_explain_region(db, "expected concrete lifetime is ",
-                                           conc_region, "");
-            }
             Sorts(values) => {
                 let expected_str = values.expected.sort_string(self);
                 let found_str = values.found.sort_string(self);
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 6353c5e0dd0e0..ae05568ab4148 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -371,12 +371,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
             RegionsDoesNotOutlive(a, b) => {
                 return tcx.lift(&(a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b))
             }
-            RegionsNotSame(a, b) => {
-                return tcx.lift(&(a, b)).map(|(a, b)| RegionsNotSame(a, b))
-            }
-            RegionsNoOverlap(a, b) => {
-                return tcx.lift(&(a, b)).map(|(a, b)| RegionsNoOverlap(a, b))
-            }
             RegionsInsufficientlyPolymorphic(a, b) => {
                 return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b))
             }
@@ -1057,12 +1051,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
             RegionsDoesNotOutlive(a, b) => {
                 RegionsDoesNotOutlive(a.fold_with(folder), b.fold_with(folder))
             },
-            RegionsNotSame(a, b) => {
-                RegionsNotSame(a.fold_with(folder), b.fold_with(folder))
-            },
-            RegionsNoOverlap(a, b) => {
-                RegionsNoOverlap(a.fold_with(folder), b.fold_with(folder))
-            },
             RegionsInsufficientlyPolymorphic(a, b) => {
                 RegionsInsufficientlyPolymorphic(a, b.fold_with(folder))
             },
@@ -1088,9 +1076,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
         match *self {
             UnsafetyMismatch(x) => x.visit_with(visitor),
             AbiMismatch(x) => x.visit_with(visitor),
-            RegionsDoesNotOutlive(a, b) |
-            RegionsNotSame(a, b) |
-            RegionsNoOverlap(a, b) => {
+            RegionsDoesNotOutlive(a, b) => {
                 a.visit_with(visitor) || b.visit_with(visitor)
             },
             RegionsInsufficientlyPolymorphic(_, b) |
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 0b62da306db47..e4384935e3733 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -943,6 +943,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                             }
                             None => {
                                 self.tcx.note_and_explain_region(
+                                    &self.region_maps,
                                     &mut db,
                                     "borrowed value must be valid for ",
                                     sub_scope,
@@ -955,6 +956,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                             }
                             None => {
                                 self.tcx.note_and_explain_region(
+                                    &self.region_maps,
                                     &mut db,
                                     "...but borrowed value is only valid for ",
                                     super_scope,
@@ -984,12 +986,14 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                     None => self.cmt_to_string(&err.cmt),
                 };
                 self.tcx.note_and_explain_region(
+                    &self.region_maps,
                     &mut db,
                     &format!("{} would have to be valid for ",
                             descr),
                     loan_scope,
                     "...");
                 self.tcx.note_and_explain_region(
+                    &self.region_maps,
                     &mut db,
                     &format!("...but {} is only valid for ", descr),
                     ptr_scope,
@@ -1245,14 +1249,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
     fn region_end_span(&self, region: ty::Region<'tcx>) -> Option<Span> {
         match *region {
             ty::ReScope(scope) => {
-                match scope.span(&self.tcx.hir) {
-                    Some(s) => {
-                        Some(s.end_point())
-                    }
-                    None => {
-                        None
-                    }
-                }
+                Some(scope.span(self.tcx, &self.region_maps).end_point())
             }
             _ => None
         }
diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs
index 4583d80b83ddc..5c0388a020c76 100644
--- a/src/librustc_mir/build/block.rs
+++ b/src/librustc_mir/build/block.rs
@@ -71,7 +71,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let outer_visibility_scope = this.visibility_scope;
         let source_info = this.source_info(span);
         for stmt in stmts {
-            let Stmt { span, kind, opt_destruction_extent } = this.hir.mirror(stmt);
+            let Stmt { kind, opt_destruction_extent } = this.hir.mirror(stmt);
             match kind {
                 StmtKind::Expr { scope, expr } => {
                     unpack!(block = this.in_opt_scope(
@@ -83,15 +83,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         }));
                 }
                 StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => {
-                    let tcx = this.hir.tcx();
-
                     // Enter the remainder scope, i.e. the bindings' destruction scope.
                     this.push_scope((remainder_scope, source_info));
                     let_extent_stack.push(remainder_scope);
 
                     // Declare the bindings, which may create a visibility scope.
-                    let remainder_span = remainder_scope.span(&tcx.hir);
-                    let remainder_span = remainder_span.unwrap_or(span);
+                    let remainder_span = remainder_scope.span(this.hir.tcx(),
+                                                              &this.hir.region_maps);
                     let scope = this.declare_bindings(None, remainder_span, &pattern);
 
                     // Evaluate the initializer, if present.
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 90f9c1c0d5f56..2471d8c2c56f7 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -633,8 +633,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 if let DropKind::Value { .. } = drop_kind {
                     scope.needs_cleanup = true;
                 }
-                let tcx = self.hir.tcx();
-                let extent_span = extent.span(&tcx.hir).unwrap();
+                let extent_span = extent.span(self.hir.tcx(), &self.hir.region_maps);
                 // Attribute scope exit drops to scope's closing brace
                 let scope_end = extent_span.with_lo(extent_span.hi());
                 scope.drops.push(DropData {
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index 61d128fc84782..d38c72c37e80f 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -45,7 +45,6 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             hir::StmtExpr(ref expr, id) |
             hir::StmtSemi(ref expr, id) => {
                 result.push(StmtRef::Mirror(Box::new(Stmt {
-                    span: stmt.span,
                     kind: StmtKind::Expr {
                         scope: CodeExtent::Misc(id),
                         expr: expr.to_ref(),
@@ -69,7 +68,6 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                                         cx.tables(),
                                                         &local.pat);
                         result.push(StmtRef::Mirror(Box::new(Stmt {
-                            span: stmt.span,
                             kind: StmtKind::Let {
                                 remainder_scope: remainder_extent,
                                 init_scope: CodeExtent::Misc(id),
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 9bd5df16a14e9..58051aaecdaab 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -46,7 +46,6 @@ pub enum StmtRef<'tcx> {
 
 #[derive(Clone, Debug)]
 pub struct Stmt<'tcx> {
-    pub span: Span,
     pub kind: StmtKind<'tcx>,
     pub opt_destruction_extent: Option<CodeExtent>,
 }
diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs
index e9d400c64393b..46948b687d26d 100644
--- a/src/librustc_typeck/check/generator_interior.rs
+++ b/src/librustc_typeck/check/generator_interior.rs
@@ -13,7 +13,6 @@
 //! is calculated in `rustc_mir::transform::generator` and may be a subset of the
 //! types computed here.
 
-use log;
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::{self, Body, Pat, PatKind, Expr};
@@ -36,18 +35,15 @@ impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> {
     fn record(&mut self, ty: Ty<'tcx>, scope: Option<CodeExtent>, expr: Option<&'tcx Expr>) {
         use syntax_pos::DUMMY_SP;
 
-        let live_across_yield = scope.map(|s| {
-            self.fcx.tcx.yield_in_extent(s, &mut self.cache).is_some()
-        }).unwrap_or(true);
+        let live_across_yield = scope.map_or(Some(DUMMY_SP), |s| {
+            self.fcx.tcx.yield_in_extent(s, &mut self.cache)
+        });
 
-        if live_across_yield {
+        if let Some(span) = live_across_yield {
             let ty = self.fcx.resolve_type_vars_if_possible(&ty);
 
-            if log_enabled!(log::LogLevel::Debug) {
-                let span = scope.map(|s| s.span(&self.fcx.tcx.hir).unwrap_or(DUMMY_SP));
-                debug!("type in expr = {:?}, scope = {:?}, type = {:?}, span = {:?}",
-                       expr, scope, ty, span);
-            }
+            debug!("type in expr = {:?}, scope = {:?}, type = {:?}, span = {:?}",
+                   expr, scope, ty, span);
 
             // Map the type to the number of types added before it
             let entries = self.types.len();
diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr
index b7479f15b1812..d928a6a0a8e64 100644
--- a/src/test/ui/mismatched_types/closure-mismatch.stderr
+++ b/src/test/ui/mismatched_types/closure-mismatch.stderr
@@ -4,7 +4,6 @@ error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/closure-mismatch.r
 18 |     baz(|_| ());
    |     ^^^ expected bound lifetime parameter, found concrete lifetime
    |
-   = note: concrete lifetime that was found is lifetime '_#0r
    = note: required because of the requirements on the impl of `Foo` for `[closure@$DIR/closure-mismatch.rs:18:9: 18:15]`
    = note: required by `baz`
 

From e4996ec49c832610f3044f49437b16527f2a726f Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Tue, 29 Aug 2017 19:24:49 +0300
Subject: [PATCH 3/3] rustc: use hir::ItemLocalId instead of ast::NodeId in
 CodeExtent.

---
 src/librustc/cfg/construct.rs                 |  10 +-
 src/librustc/cfg/graphviz.rs                  |   3 +-
 src/librustc/infer/error_reporting/mod.rs     |   2 +-
 src/librustc/middle/expr_use_visitor.rs       |  12 +-
 src/librustc/middle/mem_categorization.rs     |   5 +-
 src/librustc/middle/region.rs                 | 336 ++++++++----------
 src/librustc/traits/mod.rs                    |   2 +-
 src/librustc/ty/mod.rs                        |   5 -
 src/librustc/util/ppaux.rs                    |  19 +-
 src/librustc_borrowck/borrowck/check_loans.rs |  16 +-
 .../borrowck/gather_loans/lifetime.rs         |   3 +-
 .../borrowck/gather_loans/mod.rs              |  11 +-
 src/librustc_borrowck/borrowck/mod.rs         |  42 +--
 src/librustc_borrowck/borrowck/move_data.rs   |   6 +-
 src/librustc_driver/test.rs                   |  30 +-
 src/librustc_lint/builtin.rs                  |   2 +-
 src/librustc_mir/build/matches/mod.rs         |   3 +-
 src/librustc_mir/build/mod.rs                 |   4 +-
 src/librustc_mir/hair/cx/block.rs             |  24 +-
 src/librustc_mir/hair/cx/expr.rs              |  22 +-
 src/librustc_typeck/check/compare_method.rs   |   2 +-
 src/librustc_typeck/check/dropck.rs           |   2 +-
 .../check/generator_interior.rs               |  10 +-
 src/librustc_typeck/check/mod.rs              |   5 +-
 src/librustc_typeck/check/regionck.rs         |  18 +-
 src/librustc_typeck/coherence/builtin.rs      |   2 +-
 src/test/mir-opt/end_region_1.rs              |   6 +-
 src/test/mir-opt/end_region_2.rs              |  14 +-
 src/test/mir-opt/end_region_3.rs              |  14 +-
 src/test/mir-opt/end_region_4.rs              |  14 +-
 src/test/mir-opt/end_region_5.rs              |  14 +-
 src/test/mir-opt/end_region_6.rs              |  18 +-
 src/test/mir-opt/end_region_7.rs              |   6 +-
 src/test/mir-opt/end_region_8.rs              |  16 +-
 src/test/mir-opt/validate_1.rs                |  18 +-
 src/test/mir-opt/validate_3.rs                |  14 +-
 src/test/mir-opt/validate_5.rs                |   6 +-
 37 files changed, 333 insertions(+), 403 deletions(-)

diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 1448fb7c528c6..8908bcb886559 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -582,10 +582,10 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                         target_scope: CodeExtent,
                         to_index: CFGIndex) {
         let mut data = CFGEdgeData { exiting_scopes: vec![] };
-        let mut scope = CodeExtent::Misc(from_expr.id);
+        let mut scope = CodeExtent::Misc(from_expr.hir_id.local_id);
         let region_maps = self.tcx.region_maps(self.owner_def_id);
         while scope != target_scope {
-            data.exiting_scopes.push(self.tcx.hir.node_to_hir_id(scope.node_id()).local_id);
+            data.exiting_scopes.push(scope.item_local_id());
             scope = region_maps.encl_scope(scope);
         }
         self.graph.add_edge(from_index, to_index, data);
@@ -612,7 +612,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             hir::ScopeTarget::Block(block_expr_id) => {
                 for b in &self.breakable_block_scopes {
                     if b.block_expr_id == self.tcx.hir.node_to_hir_id(block_expr_id).local_id {
-                        return (CodeExtent::Misc(block_expr_id), match scope_cf_kind {
+                        let scope_id = self.tcx.hir.node_to_hir_id(block_expr_id).local_id;
+                        return (CodeExtent::Misc(scope_id), match scope_cf_kind {
                             ScopeCfKind::Break => b.break_index,
                             ScopeCfKind::Continue => bug!("can't continue to block"),
                         });
@@ -623,7 +624,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(loop_id)) => {
                 for l in &self.loop_scopes {
                     if l.loop_id == self.tcx.hir.node_to_hir_id(loop_id).local_id {
-                        return (CodeExtent::Misc(loop_id), match scope_cf_kind {
+                        let scope_id = self.tcx.hir.node_to_hir_id(loop_id).local_id;
+                        return (CodeExtent::Misc(scope_id), match scope_cf_kind {
                             ScopeCfKind::Break => l.break_index,
                             ScopeCfKind::Continue => l.continue_index,
                         });
diff --git a/src/librustc/cfg/graphviz.rs b/src/librustc/cfg/graphviz.rs
index fa034744b62e2..9241240caf043 100644
--- a/src/librustc/cfg/graphviz.rs
+++ b/src/librustc/cfg/graphviz.rs
@@ -32,8 +32,9 @@ pub struct LabelledCFG<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> LabelledCFG<'a, 'tcx> {
     fn local_id_to_string(&self, local_id: hir::ItemLocalId) -> String {
+        assert!(self.cfg.owner_def_id.is_local());
         let node_id = self.tcx.hir.hir_to_node_id(hir::HirId {
-            owner: self.tcx.closure_base_def_id(self.cfg.owner_def_id).index,
+            owner: self.tcx.hir.def_index_to_hir_id(self.cfg.owner_def_id.index).owner,
             local_id
         });
         let s = self.tcx.hir.node_to_string(node_id);
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index d86626c210e14..90d781c6e3664 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -132,7 +132,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                             prefix, scope, suffix)
                 };
                 let span = scope.span(self, region_maps);
-                let tag = match self.hir.find(scope.node_id()) {
+                let tag = match self.hir.find(scope.node_id(self, region_maps)) {
                     Some(hir_map::NodeBlock(_)) => "block",
                     Some(hir_map::NodeExpr(expr)) => match expr.node {
                         hir::ExprCall(..) => "call",
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index e36e1f470eb69..1589ba6027590 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -23,7 +23,7 @@ use hir::def::Def;
 use hir::def_id::{DefId};
 use infer::InferCtxt;
 use middle::mem_categorization as mc;
-use middle::region::RegionMaps;
+use middle::region::{CodeExtent, RegionMaps};
 use ty::{self, TyCtxt, adjustment};
 
 use hir::{self, PatKind};
@@ -298,7 +298,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         for arg in &body.arguments {
             let arg_ty = return_if_err!(self.mc.node_ty(arg.pat.hir_id));
 
-            let fn_body_scope_r = self.tcx().node_scope_region(body.value.id);
+            let fn_body_scope_r =
+                self.tcx().mk_region(ty::ReScope(CodeExtent::Misc(body.value.hir_id.local_id)));
             let arg_cmt = self.mc.cat_rvalue(
                 arg.id,
                 arg.pat.span,
@@ -542,16 +543,17 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
             ty::TyError => { }
             _ => {
                 let def_id = self.mc.tables.type_dependent_defs()[call.hir_id].def_id();
+                let call_scope = CodeExtent::Misc(call.hir_id.local_id);
                 match OverloadedCallType::from_method_id(self.tcx(), def_id) {
                     FnMutOverloadedCall => {
-                        let call_scope_r = self.tcx().node_scope_region(call.id);
+                        let call_scope_r = self.tcx().mk_region(ty::ReScope(call_scope));
                         self.borrow_expr(callee,
                                          call_scope_r,
                                          ty::MutBorrow,
                                          ClosureInvocation);
                     }
                     FnOverloadedCall => {
-                        let call_scope_r = self.tcx().node_scope_region(call.id);
+                        let call_scope_r = self.tcx().mk_region(ty::ReScope(call_scope));
                         self.borrow_expr(callee,
                                          call_scope_r,
                                          ty::ImmBorrow,
@@ -749,7 +751,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                 // Converting from a &T to *T (or &mut T to *mut T) is
                 // treated as borrowing it for the enclosing temporary
                 // scope.
-                let r = self.tcx().node_scope_region(expr.id);
+                let r = self.tcx().mk_region(ty::ReScope(CodeExtent::Misc(expr.hir_id.local_id)));
 
                 self.delegate.borrow(expr.id,
                                      expr.span,
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 034861131e86e..fdab71ee00441 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -861,8 +861,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
 
     /// Returns the lifetime of a temporary created by expr with id `id`.
     /// This could be `'static` if `id` is part of a constant expression.
-    pub fn temporary_scope(&self, id: ast::NodeId) -> ty::Region<'tcx>
-    {
+    pub fn temporary_scope(&self, id: hir::ItemLocalId) -> ty::Region<'tcx> {
         let scope = self.region_maps.temporary_scope(id);
         self.tcx.mk_region(match scope {
             Some(scope) => ty::ReScope(scope),
@@ -890,7 +889,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         let re = if promotable {
             self.tcx.types.re_static
         } else {
-            self.temporary_scope(id)
+            self.temporary_scope(self.tcx.hir.node_to_hir_id(id).local_id)
         };
         let ret = self.cat_rvalue(id, span, re, expr_ty);
         debug!("cat_rvalue_node ret {:?}", ret);
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 10a21a582f554..f58d1a0b41fec 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -16,15 +16,15 @@
 //! Most of the documentation on regions can be found in
 //! `middle/infer/region_inference/README.md`
 
-use util::nodemap::{FxHashMap, NodeMap, NodeSet};
+use util::nodemap::{FxHashMap, FxHashSet};
 use ty;
 
+use std::collections::hash_map::Entry;
 use std::mem;
 use std::rc::Rc;
 use syntax::codemap;
 use syntax::ast;
-use syntax::ast::NodeId;
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
 use ty::TyCtxt;
 use ty::maps::Providers;
 
@@ -32,7 +32,6 @@ use hir;
 use hir::def_id::DefId;
 use hir::intravisit::{self, Visitor, NestedVisitorMap};
 use hir::{Block, Arm, Pat, PatKind, Stmt, Expr, Local};
-use hir::map::Node;
 use mir::transform::MirSource;
 
 /// CodeExtent represents a statically-describable extent that can be
@@ -98,18 +97,18 @@ use mir::transform::MirSource;
 /// generated via deriving here.
 #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, RustcEncodable, RustcDecodable)]
 pub enum CodeExtent {
-    Misc(ast::NodeId),
+    Misc(hir::ItemLocalId),
 
     // extent of the call-site for a function or closure (outlives
     // the parameters as well as the body).
-    CallSiteScope(hir::BodyId),
+    CallSiteScope(hir::ItemLocalId),
 
     // extent of parameters passed to a function or closure (they
     // outlive its body)
-    ParameterScope(hir::BodyId),
+    ParameterScope(hir::ItemLocalId),
 
     // extent of destructors for temporaries of node-id
-    DestructionScope(ast::NodeId),
+    DestructionScope(hir::ItemLocalId),
 
     // extent of code following a `let id = expr;` binding in a block
     Remainder(BlockRemainder)
@@ -135,25 +134,37 @@ pub enum CodeExtent {
 #[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable,
          RustcDecodable, Debug, Copy)]
 pub struct BlockRemainder {
-    pub block: ast::NodeId,
+    pub block: hir::ItemLocalId,
     pub first_statement_index: u32,
 }
 
 impl CodeExtent {
-    /// Returns a node id associated with this scope.
+    /// Returns a item-local id associated with this scope.
     ///
     /// NB: likely to be replaced as API is refined; e.g. pnkfelix
     /// anticipates `fn entry_node_id` and `fn each_exit_node_id`.
-    pub fn node_id(&self) -> ast::NodeId {
+    pub fn item_local_id(&self) -> hir::ItemLocalId {
         match *self {
-            CodeExtent::Misc(node_id) => node_id,
+            CodeExtent::Misc(id) => id,
 
             // These cases all return rough approximations to the
             // precise extent denoted by `self`.
             CodeExtent::Remainder(br) => br.block,
-            CodeExtent::DestructionScope(node_id) => node_id,
-            CodeExtent::CallSiteScope(body_id) |
-            CodeExtent::ParameterScope(body_id) => body_id.node_id,
+            CodeExtent::DestructionScope(id) |
+            CodeExtent::CallSiteScope(id) |
+            CodeExtent::ParameterScope(id) => id,
+        }
+    }
+
+    pub fn node_id(&self, tcx: TyCtxt, region_maps: &RegionMaps) -> ast::NodeId {
+        match region_maps.root_body {
+            Some(hir_id) => {
+                tcx.hir.hir_to_node_id(hir::HirId {
+                    owner: hir_id.owner,
+                    local_id: self.item_local_id()
+                })
+            }
+            None => ast::DUMMY_NODE_ID
         }
     }
 
@@ -161,12 +172,13 @@ impl CodeExtent {
     /// returned span may not correspond to the span of any node id in
     /// the AST.
     pub fn span(&self, tcx: TyCtxt, region_maps: &RegionMaps) -> Span {
-        let root_node = region_maps.root_body.unwrap().node_id;
-        assert_eq!(DefId::local(tcx.hir.node_to_hir_id(self.node_id()).owner),
-                   DefId::local(tcx.hir.node_to_hir_id(root_node).owner));
-        let span = tcx.hir.span(self.node_id());
+        let node_id = self.node_id(tcx, region_maps);
+        if node_id == ast::DUMMY_NODE_ID {
+            return DUMMY_SP;
+        }
+        let span = tcx.hir.span(node_id);
         if let CodeExtent::Remainder(r) = *self {
-            if let hir::map::NodeBlock(ref blk) = tcx.hir.get(r.block) {
+            if let hir::map::NodeBlock(ref blk) = tcx.hir.get(node_id) {
                 // Want span for extent starting after the
                 // indexed statement and ending at end of
                 // `blk`; reuse span of `blk` and shift `lo`
@@ -189,9 +201,10 @@ impl CodeExtent {
 }
 
 /// The region maps encode information about region relationships.
+#[derive(Default)]
 pub struct RegionMaps {
     /// If not empty, this body is the root of this region hierarchy.
-    root_body: Option<hir::BodyId>,
+    root_body: Option<hir::HirId>,
 
     /// The parent of the root body owner, if the latter is an
     /// an associated const or method, as impls/traits can also
@@ -208,10 +221,10 @@ pub struct RegionMaps {
 
     /// `var_map` maps from a variable or binding id to the block in
     /// which that variable is declared.
-    var_map: NodeMap<CodeExtent>,
+    var_map: FxHashMap<hir::ItemLocalId, CodeExtent>,
 
     /// maps from a node-id to the associated destruction scope (if any)
-    destruction_scopes: NodeMap<CodeExtent>,
+    destruction_scopes: FxHashMap<hir::ItemLocalId, CodeExtent>,
 
     /// `rvalue_scopes` includes entries for those expressions whose cleanup scope is
     /// larger than the default. The map goes from the expression id
@@ -221,7 +234,7 @@ pub struct RegionMaps {
     /// block (see `terminating_scopes`).
     /// In constants, None is used to indicate that certain expressions
     /// escape into 'static and should have no local cleanup scope.
-    rvalue_scopes: NodeMap<Option<CodeExtent>>,
+    rvalue_scopes: FxHashMap<hir::ItemLocalId, Option<CodeExtent>>,
 
     /// Encodes the hierarchy of fn bodies. Every fn body (including
     /// closures) forms its own distinct region hierarchy, rooted in
@@ -233,7 +246,11 @@ pub struct RegionMaps {
     /// closure defined by that fn. See the "Modeling closures"
     /// section of the README in infer::region_inference for
     /// more details.
-    fn_tree: NodeMap<ast::NodeId>,
+    closure_tree: FxHashMap<hir::ItemLocalId, hir::ItemLocalId>,
+
+    /// If there are any `yield` nested within a scope, this map
+    /// stores the `Span` of the first one.
+    yield_in_scope: FxHashMap<CodeExtent, Span>,
 }
 
 #[derive(Debug, Copy, Clone)]
@@ -244,7 +261,7 @@ pub struct Context {
     /// arranged into a tree. See the "Modeling closures" section of
     /// the README in infer::region_inference for more
     /// details.
-    root_id: Option<ast::NodeId>,
+    root_id: Option<hir::ItemLocalId>,
 
     /// the scope that contains any new variables declared
     var_parent: Option<CodeExtent>,
@@ -281,23 +298,11 @@ struct RegionResolutionVisitor<'a, 'tcx: 'a> {
     /// arbitrary amounts of stack space. Terminating scopes end
     /// up being contained in a DestructionScope that contains the
     /// destructor's execution.
-    terminating_scopes: NodeSet,
+    terminating_scopes: FxHashSet<hir::ItemLocalId>,
 }
 
 
 impl<'tcx> RegionMaps {
-    pub fn new() -> Self {
-        RegionMaps {
-            root_body: None,
-            root_parent: None,
-            scope_map: FxHashMap(),
-            destruction_scopes: FxHashMap(),
-            var_map: NodeMap(),
-            rvalue_scopes: NodeMap(),
-            fn_tree: NodeMap(),
-        }
-    }
-
     pub fn record_code_extent(&mut self,
                               child: CodeExtent,
                               parent: Option<CodeExtent>) {
@@ -320,46 +325,51 @@ impl<'tcx> RegionMaps {
         }
     }
 
-    pub fn each_var_scope<E>(&self, mut e:E) where E: FnMut(&ast::NodeId, CodeExtent) {
+    pub fn each_var_scope<E>(&self, mut e:E) where E: FnMut(&hir::ItemLocalId, CodeExtent) {
         for (child, &parent) in self.var_map.iter() {
             e(child, parent)
         }
     }
 
-    pub fn opt_destruction_extent(&self, n: ast::NodeId) -> Option<CodeExtent> {
+    pub fn opt_destruction_extent(&self, n: hir::ItemLocalId) -> Option<CodeExtent> {
         self.destruction_scopes.get(&n).cloned()
     }
 
-    /// Records that `sub_fn` is defined within `sup_fn`. These ids
+    /// Records that `sub_closure` is defined within `sup_closure`. These ids
     /// should be the id of the block that is the fn body, which is
     /// also the root of the region hierarchy for that fn.
-    fn record_fn_parent(&mut self, sub_fn: ast::NodeId, sup_fn: ast::NodeId) {
-        debug!("record_fn_parent(sub_fn={:?}, sup_fn={:?})", sub_fn, sup_fn);
-        assert!(sub_fn != sup_fn);
-        let previous = self.fn_tree.insert(sub_fn, sup_fn);
+    fn record_closure_parent(&mut self,
+                             sub_closure: hir::ItemLocalId,
+                             sup_closure: hir::ItemLocalId) {
+        debug!("record_closure_parent(sub_closure={:?}, sup_closure={:?})",
+               sub_closure, sup_closure);
+        assert!(sub_closure != sup_closure);
+        let previous = self.closure_tree.insert(sub_closure, sup_closure);
         assert!(previous.is_none());
     }
 
-    fn fn_is_enclosed_by(&self, mut sub_fn: ast::NodeId, sup_fn: ast::NodeId) -> bool {
+    fn closure_is_enclosed_by(&self,
+                              mut sub_closure: hir::ItemLocalId,
+                              sup_closure: hir::ItemLocalId) -> bool {
         loop {
-            if sub_fn == sup_fn { return true; }
-            match self.fn_tree.get(&sub_fn) {
-                Some(&s) => { sub_fn = s; }
+            if sub_closure == sup_closure { return true; }
+            match self.closure_tree.get(&sub_closure) {
+                Some(&s) => { sub_closure = s; }
                 None => { return false; }
             }
         }
     }
 
-    fn record_var_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent) {
+    fn record_var_scope(&mut self, var: hir::ItemLocalId, lifetime: CodeExtent) {
         debug!("record_var_scope(sub={:?}, sup={:?})", var, lifetime);
-        assert!(var != lifetime.node_id());
+        assert!(var != lifetime.item_local_id());
         self.var_map.insert(var, lifetime);
     }
 
-    fn record_rvalue_scope(&mut self, var: ast::NodeId, lifetime: Option<CodeExtent>) {
+    fn record_rvalue_scope(&mut self, var: hir::ItemLocalId, lifetime: Option<CodeExtent>) {
         debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
         if let Some(lifetime) = lifetime {
-            assert!(var != lifetime.node_id());
+            assert!(var != lifetime.item_local_id());
         }
         self.rvalue_scopes.insert(var, lifetime);
     }
@@ -376,14 +386,14 @@ impl<'tcx> RegionMaps {
     }
 
     /// Returns the lifetime of the local variable `var_id`
-    pub fn var_scope(&self, var_id: ast::NodeId) -> CodeExtent {
+    pub fn var_scope(&self, var_id: hir::ItemLocalId) -> CodeExtent {
         match self.var_map.get(&var_id) {
             Some(&r) => r,
             None => { bug!("no enclosing scope for id {:?}", var_id); }
         }
     }
 
-    pub fn temporary_scope(&self, expr_id: ast::NodeId) -> Option<CodeExtent> {
+    pub fn temporary_scope(&self, expr_id: hir::ItemLocalId) -> Option<CodeExtent> {
         //! Returns the scope when temp created by expr_id will be cleaned up
 
         // check for a designated rvalue scope
@@ -413,7 +423,7 @@ impl<'tcx> RegionMaps {
         return None;
     }
 
-    pub fn var_region(&self, id: ast::NodeId) -> ty::RegionKind {
+    pub fn var_region(&self, id: hir::ItemLocalId) -> ty::RegionKind {
         //! Returns the lifetime of the variable `id`.
 
         let scope = ty::ReScope(self.var_scope(id));
@@ -493,10 +503,10 @@ impl<'tcx> RegionMaps {
             return match (a_root_scope, b_root_scope) {
                 (CodeExtent::DestructionScope(a_root_id),
                  CodeExtent::DestructionScope(b_root_id)) => {
-                    if self.fn_is_enclosed_by(a_root_id, b_root_id) {
+                    if self.closure_is_enclosed_by(a_root_id, b_root_id) {
                         // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a`
                         scope_b
-                    } else if self.fn_is_enclosed_by(b_root_id, a_root_id) {
+                    } else if self.closure_is_enclosed_by(b_root_id, a_root_id) {
                         // `b` is enclosed by `a`, hence `a` is the ancestor of everything in `b`
                         scope_a
                     } else {
@@ -561,20 +571,23 @@ impl<'tcx> RegionMaps {
         let param_owner = tcx.parent_def_id(br.def_id).unwrap();
 
         let param_owner_id = tcx.hir.as_local_node_id(param_owner).unwrap();
-        let body_id = tcx.hir.maybe_body_owned_by(param_owner_id).unwrap_or_else(|| {
+        let scope = tcx.hir.maybe_body_owned_by(param_owner_id).map(|body_id| {
+            tcx.hir.body(body_id).value.hir_id.local_id
+        }).unwrap_or_else(|| {
             // The lifetime was defined on node that doesn't own a body,
             // which in practice can only mean a trait or an impl, that
             // is the parent of a method, and that is enforced below.
             assert_eq!(Some(param_owner_id), self.root_parent,
-                       "free_extent: {:?} not recognized by the region maps for {:?}",
+                       "free_extent: {:?} not recognized by the region maps for {:?} / {:?}",
                        param_owner,
-                       self.root_body.map(|body| tcx.hir.body_owner_def_id(body)));
+                       self.root_parent.map(|id| tcx.hir.local_def_id(id)),
+                       self.root_body.map(|hir_id| DefId::local(hir_id.owner)));
 
             // The trait/impl lifetime is in scope for the method's body.
-            self.root_body.unwrap()
+            self.root_body.unwrap().local_id
         });
 
-        CodeExtent::CallSiteScope(body_id)
+        CodeExtent::CallSiteScope(scope)
     }
 
     /// Assuming that the provided region was defined within this `RegionMaps`,
@@ -593,13 +606,20 @@ impl<'tcx> RegionMaps {
         assert_eq!(param_owner, fr.scope);
 
         let param_owner_id = tcx.hir.as_local_node_id(param_owner).unwrap();
-        CodeExtent::CallSiteScope(tcx.hir.body_owned_by(param_owner_id))
+        let body_id = tcx.hir.body_owned_by(param_owner_id);
+        CodeExtent::CallSiteScope(tcx.hir.body(body_id).value.hir_id.local_id)
+    }
+
+    /// Checks whether the given code extent contains a `yield`. If so,
+    /// returns `Some(span)` with the span of a yield we found.
+    pub fn yield_in_scope(&self, scope: CodeExtent) -> Option<Span> {
+        self.yield_in_scope.get(&scope).cloned()
     }
 }
 
 /// Records the lifetime of a local variable as `cx.var_parent`
 fn record_var_lifetime(visitor: &mut RegionResolutionVisitor,
-                       var_id: ast::NodeId,
+                       var_id: hir::ItemLocalId,
                        _sp: Span) {
     match visitor.cx.var_parent {
         None => {
@@ -642,7 +662,7 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
     // `other_argument()` has run and also the call to `quux(..)`
     // itself has returned.
 
-    visitor.enter_node_extent_with_dtor(blk.id);
+    visitor.enter_node_extent_with_dtor(blk.hir_id.local_id);
     visitor.cx.var_parent = visitor.cx.parent;
 
     {
@@ -661,7 +681,7 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
                 // block itself as a parent.
                 visitor.enter_code_extent(
                     CodeExtent::Remainder(BlockRemainder {
-                        block: blk.id,
+                        block: blk.hir_id.local_id,
                         first_statement_index: i as u32
                     })
                 );
@@ -676,28 +696,28 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
 }
 
 fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, arm: &'tcx hir::Arm) {
-    visitor.terminating_scopes.insert(arm.body.id);
+    visitor.terminating_scopes.insert(arm.body.hir_id.local_id);
 
     if let Some(ref expr) = arm.guard {
-        visitor.terminating_scopes.insert(expr.id);
+        visitor.terminating_scopes.insert(expr.hir_id.local_id);
     }
 
     intravisit::walk_arm(visitor, arm);
 }
 
 fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &'tcx hir::Pat) {
-    visitor.record_code_extent(CodeExtent::Misc(pat.id));
+    visitor.record_code_extent(CodeExtent::Misc(pat.hir_id.local_id));
 
     // If this is a binding then record the lifetime of that binding.
     if let PatKind::Binding(..) = pat.node {
-        record_var_lifetime(visitor, pat.id, pat.span);
+        record_var_lifetime(visitor, pat.hir_id.local_id, pat.span);
     }
 
     intravisit::walk_pat(visitor, pat);
 }
 
 fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, stmt: &'tcx hir::Stmt) {
-    let stmt_id = stmt.node.id();
+    let stmt_id = visitor.tcx.hir.node_to_hir_id(stmt.node.id()).local_id;
     debug!("resolve_stmt(stmt.id={:?})", stmt_id);
 
     // Every statement will clean up the temporaries created during
@@ -719,11 +739,11 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
     debug!("resolve_expr(expr.id={:?})", expr.id);
 
     let prev_cx = visitor.cx;
-    visitor.enter_node_extent_with_dtor(expr.id);
+    visitor.enter_node_extent_with_dtor(expr.hir_id.local_id);
 
     {
         let terminating_scopes = &mut visitor.terminating_scopes;
-        let mut terminating = |id: ast::NodeId| {
+        let mut terminating = |id: hir::ItemLocalId| {
             terminating_scopes.insert(id);
         };
         match expr.node {
@@ -735,27 +755,27 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
             hir::ExprBinary(codemap::Spanned { node: hir::BiOr, .. }, _, ref r) => {
                 // For shortcircuiting operators, mark the RHS as a terminating
                 // scope since it only executes conditionally.
-                terminating(r.id);
+                terminating(r.hir_id.local_id);
             }
 
             hir::ExprIf(ref expr, ref then, Some(ref otherwise)) => {
-                terminating(expr.id);
-                terminating(then.id);
-                terminating(otherwise.id);
+                terminating(expr.hir_id.local_id);
+                terminating(then.hir_id.local_id);
+                terminating(otherwise.hir_id.local_id);
             }
 
             hir::ExprIf(ref expr, ref then, None) => {
-                terminating(expr.id);
-                terminating(then.id);
+                terminating(expr.hir_id.local_id);
+                terminating(then.hir_id.local_id);
             }
 
             hir::ExprLoop(ref body, _, _) => {
-                terminating(body.id);
+                terminating(body.hir_id.local_id);
             }
 
             hir::ExprWhile(ref expr, ref body, _) => {
-                terminating(expr.id);
-                terminating(body.id);
+                terminating(expr.hir_id.local_id);
+                terminating(body.hir_id.local_id);
             }
 
             hir::ExprMatch(..) => {
@@ -784,6 +804,29 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
                 // record_superlifetime(new_cx, expr.callee_id);
             }
 
+            hir::ExprYield(..) => {
+                // Mark this expr's scope and all parent scopes as containing `yield`.
+                let mut scope = CodeExtent::Misc(expr.hir_id.local_id);
+                loop {
+                    match visitor.region_maps.yield_in_scope.entry(scope) {
+                        // Another `yield` has already been found.
+                        Entry::Occupied(_) => break,
+
+                        Entry::Vacant(entry) => {
+                            entry.insert(expr.span);
+                        }
+                    }
+
+                    // Keep traversing up while we can.
+                    match visitor.region_maps.scope_map.get(&scope) {
+                        // Don't cross from closure bodies to their parent.
+                        Some(&CodeExtent::CallSiteScope(_)) => break,
+                        Some(&superscope) => scope = superscope,
+                        None => break
+                    }
+                }
+            }
+
             _ => {}
         }
     }
@@ -1014,7 +1057,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
             // because in trans if we must compile e.g. `*rvalue()`
             // into a temporary, we request the temporary scope of the
             // outer expression.
-            visitor.region_maps.record_rvalue_scope(expr.id, blk_scope);
+            visitor.region_maps.record_rvalue_scope(expr.hir_id.local_id, blk_scope);
 
             match expr.node {
                 hir::ExprAddrOf(_, ref subexpr) |
@@ -1046,7 +1089,7 @@ impl<'a, 'tcx> RegionResolutionVisitor<'a, 'tcx> {
         self.cx.parent = Some(child_scope);
     }
 
-    fn enter_node_extent_with_dtor(&mut self, id: ast::NodeId) {
+    fn enter_node_extent_with_dtor(&mut self, id: hir::ItemLocalId) {
         // If node was previously marked as a terminating scope during the
         // recursive visit of its parent node in the AST, then we need to
         // account for the destruction scope representing the extent of
@@ -1078,16 +1121,16 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
                self.cx.parent);
 
         let outer_cx = self.cx;
-        let outer_ts = mem::replace(&mut self.terminating_scopes, NodeSet());
-        self.terminating_scopes.insert(body_id.node_id);
+        let outer_ts = mem::replace(&mut self.terminating_scopes, FxHashSet());
+        self.terminating_scopes.insert(body.value.hir_id.local_id);
 
         if let Some(root_id) = self.cx.root_id {
-            self.region_maps.record_fn_parent(body_id.node_id, root_id);
+            self.region_maps.record_closure_parent(body.value.hir_id.local_id, root_id);
         }
-        self.cx.root_id = Some(body_id.node_id);
+        self.cx.root_id = Some(body.value.hir_id.local_id);
 
-        self.enter_code_extent(CodeExtent::CallSiteScope(body_id));
-        self.enter_code_extent(CodeExtent::ParameterScope(body_id));
+        self.enter_code_extent(CodeExtent::CallSiteScope(body.value.hir_id.local_id));
+        self.enter_code_extent(CodeExtent::ParameterScope(body.value.hir_id.local_id));
 
         // The arguments and `self` are parented to the fn.
         self.cx.var_parent = self.cx.parent.take();
@@ -1153,19 +1196,20 @@ fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
     }
 
     let id = tcx.hir.as_local_node_id(def_id).unwrap();
-    let maps = if let Some(body) = tcx.hir.maybe_body_owned_by(id) {
+    let maps = if let Some(body_id) = tcx.hir.maybe_body_owned_by(id) {
         let mut visitor = RegionResolutionVisitor {
             tcx,
-            region_maps: RegionMaps::new(),
+            region_maps: RegionMaps::default(),
             cx: Context {
                 root_id: None,
                 parent: None,
                 var_parent: None,
             },
-            terminating_scopes: NodeSet(),
+            terminating_scopes: FxHashSet(),
         };
 
-        visitor.region_maps.root_body = Some(body);
+        let body = tcx.hir.body(body_id);
+        visitor.region_maps.root_body = Some(body.value.hir_id);
 
         // If the item is an associated const or a method,
         // record its impl/trait parent, as it can also have
@@ -1178,112 +1222,16 @@ fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
             _ => {}
         }
 
-        visitor.visit_body(tcx.hir.body(body));
+        visitor.visit_body(body);
 
         visitor.region_maps
     } else {
-        RegionMaps::new()
+        RegionMaps::default()
     };
 
     Rc::new(maps)
 }
 
-struct YieldFinder<'a> {
-    cache: &'a mut FxHashMap<NodeId, Option<Span>>,
-    result: Option<Span>,
-}
-
-impl<'a> YieldFinder<'a> {
-    fn lookup<F: FnOnce(&mut Self)>(&mut self, id: NodeId, f: F) {
-        // Don't traverse further if we found a yield expression
-        if self.result.is_some() {
-            return;
-        }
-
-        // See if there's an entry in the cache
-        if let Some(result) = self.cache.get(&id) {
-            self.result = *result;
-            return;
-        }
-
-        // Otherwise calculate the result and insert it into the cache
-        f(self);
-        self.cache.insert(id, self.result);
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for YieldFinder<'a> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
-        if let hir::ExprYield(..) = expr.node {
-            self.result = Some(expr.span);
-            return;
-        }
-
-        self.lookup(expr.id, |this| {
-            intravisit::walk_expr(this, expr);
-        });
-    }
-
-    fn visit_block(&mut self, block: &'tcx hir::Block) {
-        self.lookup(block.id, |this| {
-            intravisit::walk_block(this, block);
-        });
-    }
-}
-
-impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-    /// Checks whether the given code extent contains a `yield`. If so,
-    /// returns `Some(span)` with the span of a yield we found.
-    pub fn yield_in_extent(self,
-                          extent: CodeExtent,
-                          cache: &mut FxHashMap<NodeId, Option<Span>>) -> Option<Span> {
-        let mut finder = YieldFinder {
-            cache,
-            result: None,
-        };
-
-        match extent {
-            CodeExtent::DestructionScope(node_id) |
-            CodeExtent::Misc(node_id) => {
-                match self.hir.get(node_id) {
-                    Node::NodeItem(_) |
-                    Node::NodeTraitItem(_) |
-                    Node::NodeImplItem(_) => {
-                        let body = self.hir.body(self.hir.body_owned_by(node_id));
-                        finder.visit_body(body);
-                    }
-                    Node::NodeExpr(expr) => finder.visit_expr(expr),
-                    Node::NodeStmt(stmt) => finder.visit_stmt(stmt),
-                    Node::NodeBlock(block) => finder.visit_block(block),
-                    _ => bug!(),
-                }
-            }
-
-            CodeExtent::CallSiteScope(body_id) |
-            CodeExtent::ParameterScope(body_id) => {
-                finder.visit_body(self.hir.body(body_id))
-            }
-
-            CodeExtent::Remainder(r) => {
-                if let Node::NodeBlock(block) = self.hir.get(r.block) {
-                    for stmt in &block.stmts[(r.first_statement_index as usize + 1)..] {
-                        finder.visit_stmt(stmt);
-                    }
-                    block.expr.as_ref().map(|e| finder.visit_expr(e));
-                } else {
-                    bug!()
-                }
-            }
-        }
-
-        finder.result
-    }
-}
-
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
         region_maps,
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 019f0a709116c..35ca8eb142283 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -532,7 +532,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         debug!("normalize_param_env_or_error: normalized predicates={:?}",
             predicates);
 
-        let region_maps = RegionMaps::new();
+        let region_maps = RegionMaps::default();
         let free_regions = FreeRegionMap::new();
         infcx.resolve_regions_and_report_errors(region_context, &region_maps, &free_regions);
         let predicates = match infcx.fully_resolve(&predicates) {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index ca735599a0da6..1851e1b8d34bb 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -23,7 +23,6 @@ use middle::const_val::ConstVal;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::privacy::AccessLevels;
 use middle::resolve_lifetime::ObjectLifetimeDefault;
-use middle::region::CodeExtent;
 use mir::Mir;
 use mir::GeneratorLayout;
 use traits;
@@ -2309,10 +2308,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn node_scope_region(self, id: NodeId) -> Region<'tcx> {
-        self.mk_region(ty::ReScope(CodeExtent::Misc(id)))
-    }
-
     /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`
     /// with the name of the crate containing the impl.
     pub fn span_of_impl(self, impl_did: DefId) -> Result<Span, Symbol> {
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index a5642467474b3..2f5f31e0f63bc 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use hir::BodyId;
 use hir::def_id::DefId;
 use hir::map::definitions::DefPathData;
 use middle::region::{CodeExtent, BlockRemainder};
@@ -527,16 +526,16 @@ impl fmt::Display for ty::RegionKind {
             }
             ty::ReScope(code_extent) if identify_regions() => {
                 match code_extent {
-                    CodeExtent::Misc(node_id) =>
-                        write!(f, "'{}mce", node_id.as_u32()),
-                    CodeExtent::CallSiteScope(BodyId { node_id }) =>
-                        write!(f, "'{}cce", node_id.as_u32()),
-                    CodeExtent::ParameterScope(BodyId { node_id }) =>
-                        write!(f, "'{}pce", node_id.as_u32()),
-                    CodeExtent::DestructionScope(node_id) =>
-                        write!(f, "'{}dce", node_id.as_u32()),
+                    CodeExtent::Misc(id) =>
+                        write!(f, "'{}mce", id.as_usize()),
+                    CodeExtent::CallSiteScope(id) =>
+                        write!(f, "'{}cce", id.as_usize()),
+                    CodeExtent::ParameterScope(id) =>
+                        write!(f, "'{}pce", id.as_usize()),
+                    CodeExtent::DestructionScope(id) =>
+                        write!(f, "'{}dce", id.as_usize()),
                     CodeExtent::Remainder(BlockRemainder { block, first_statement_index }) =>
-                        write!(f, "'{}_{}rce", block, first_statement_index),
+                        write!(f, "'{}_{}rce", block.as_usize(), first_statement_index),
                 }
             }
             ty::ReVar(region_vid) if identify_regions() => {
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index e83c79fb4a414..7f31c53e63caf 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -246,7 +246,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
         //! Like `each_issued_loan()`, but only considers loans that are
         //! currently in scope.
 
-        self.each_issued_loan(self.tcx().hir.node_to_hir_id(scope.node_id()).local_id, |loan| {
+        self.each_issued_loan(scope.item_local_id(), |loan| {
             if self.bccx.region_maps.is_subscope_of(scope, loan.kill_scope) {
                 op(loan)
             } else {
@@ -467,7 +467,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
             // 3. Where does old loan expire.
 
             let previous_end_span =
-                self.tcx().hir.span(old_loan.kill_scope.node_id()).end_point();
+                old_loan.kill_scope.span(self.tcx(), &self.bccx.region_maps).end_point();
 
             let mut err = match (new_loan.kind, old_loan.kind) {
                 (ty::MutBorrow, ty::MutBorrow) => {
@@ -713,12 +713,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
 
         let mut ret = UseOk;
 
-        let node_id = self.tcx().hir.hir_to_node_id(hir::HirId {
-            owner: self.tcx().closure_base_def_id(self.bccx.owner_def_id).index,
-            local_id: expr_id
-        });
         self.each_in_scope_loan_affecting_path(
-            region::CodeExtent::Misc(node_id), use_path, |loan| {
+            region::CodeExtent::Misc(expr_id), use_path, |loan| {
             if !compatible_borrow_kinds(loan.kind, borrow_kind) {
                 ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span);
                 false
@@ -837,11 +833,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
 
         // Check that we don't invalidate any outstanding loans
         if let Some(loan_path) = opt_loan_path(&assignee_cmt) {
-            let node_id = self.tcx().hir.hir_to_node_id(hir::HirId {
-                owner: self.tcx().closure_base_def_id(self.bccx.owner_def_id).index,
-                local_id: assignment_id
-            });
-            let scope = region::CodeExtent::Misc(node_id);
+            let scope = region::CodeExtent::Misc(assignment_id);
             self.each_in_scope_loan_affecting_path(scope, &loan_path, |loan| {
                 self.report_illegal_mutation(assignment_span, &loan_path, loan);
                 false
diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
index 22de3c759139d..461f1d6a43283 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
@@ -115,8 +115,9 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
                 self.bccx.tcx.mk_region(ty::ReScope(self.item_scope))
             }
             Categorization::Local(local_id) => {
+                let hir_id = self.bccx.tcx.hir.node_to_hir_id(local_id);
                 self.bccx.tcx.mk_region(ty::ReScope(
-                    self.bccx.region_maps.var_scope(local_id)))
+                    self.bccx.region_maps.var_scope(hir_id.local_id)))
             }
             Categorization::StaticItem |
             Categorization::Deref(_, mc::UnsafePtr(..)) => {
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index e14edc43904ea..5689a30fd38c0 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -43,7 +43,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
     let mut glcx = GatherLoanCtxt {
         bccx,
         all_loans: Vec::new(),
-        item_ub: region::CodeExtent::Misc(body.node_id),
+        item_ub: region::CodeExtent::Misc(bccx.tcx.hir.body(body).value.hir_id.local_id),
         move_data: MoveData::default(),
         move_error_collector: move_error::MoveErrorCollector::new(),
     };
@@ -126,7 +126,8 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> {
                bk={:?}, loan_cause={:?})",
                borrow_id, cmt, loan_region,
                bk, loan_cause);
-        self.guarantee_valid(borrow_id,
+        let hir_id = self.bccx.tcx.hir.node_to_hir_id(borrow_id);
+        self.guarantee_valid(hir_id.local_id,
                              borrow_span,
                              cmt,
                              bk,
@@ -291,13 +292,13 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
     /// reports an error.  This may entail taking out loans, which will be added to the
     /// `req_loan_map`.
     fn guarantee_valid(&mut self,
-                       borrow_id: ast::NodeId,
+                       borrow_id: hir::ItemLocalId,
                        borrow_span: Span,
                        cmt: mc::cmt<'tcx>,
                        req_kind: ty::BorrowKind,
                        loan_region: ty::Region<'tcx>,
                        cause: euv::LoanCause) {
-        debug!("guarantee_valid(borrow_id={}, cmt={:?}, \
+        debug!("guarantee_valid(borrow_id={:?}, cmt={:?}, \
                 req_mutbl={:?}, loan_region={:?})",
                borrow_id,
                cmt,
@@ -396,7 +397,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
             }
         };
 
-        debug!("guarantee_valid(borrow_id={}), loan={:?}",
+        debug!("guarantee_valid(borrow_id={:?}), loan={:?}",
                borrow_id, loan);
 
         // let loan_path = loan.loan_path;
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index e4384935e3733..25aac92c13d85 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -36,7 +36,6 @@ use rustc::middle::region::{self, RegionMaps};
 use rustc::middle::free_region::RegionRelations;
 use rustc::ty::{self, TyCtxt};
 use rustc::ty::maps::Providers;
-use rustc::util::nodemap::FxHashMap;
 use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
 
 use std::fmt;
@@ -167,10 +166,9 @@ fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>(this: &mut BorrowckCtxt<'a, 'tc
                              id_range,
                              all_loans.len());
     for (loan_idx, loan) in all_loans.iter().enumerate() {
-        loan_dfcx.add_gen(this.tcx.hir.node_to_hir_id(loan.gen_scope.node_id()).local_id,
-                          loan_idx);
+        loan_dfcx.add_gen(loan.gen_scope.item_local_id(), loan_idx);
         loan_dfcx.add_kill(KillFrom::ScopeEnd,
-                           this.tcx.hir.node_to_hir_id(loan.kill_scope.node_id()).local_id,
+                           loan.kill_scope.item_local_id(),
                            loan_idx);
     }
     loan_dfcx.add_kills_from_flow_exits(cfg);
@@ -366,10 +364,14 @@ fn closure_to_block(closure_id: DefIndex,
 impl<'a, 'tcx> LoanPath<'tcx> {
     pub fn kill_scope(&self, bccx: &BorrowckCtxt<'a, 'tcx>) -> region::CodeExtent {
         match self.kind {
-            LpVar(local_id) => bccx.region_maps.var_scope(local_id),
+            LpVar(local_id) => {
+                let hir_id = bccx.tcx.hir.node_to_hir_id(local_id);
+                bccx.region_maps.var_scope(hir_id.local_id)
+            }
             LpUpvar(upvar_id) => {
                 let block_id = closure_to_block(upvar_id.closure_expr_id, bccx.tcx);
-                region::CodeExtent::Misc(block_id)
+                let hir_id = bccx.tcx.hir.node_to_hir_id(block_id);
+                region::CodeExtent::Misc(hir_id.local_id)
             }
             LpDowncast(ref base, _) |
             LpExtend(ref base, ..) => base.kill_scope(bccx),
@@ -643,7 +645,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
         // Get type of value and span where it was previously
         // moved.
         let node_id = self.tcx.hir.hir_to_node_id(hir::HirId {
-            owner: self.tcx.closure_base_def_id(self.owner_def_id).index,
+            owner: self.body.value.hir_id.owner,
             local_id: the_move.id
         });
         let (move_span, move_note) = match the_move.kind {
@@ -818,7 +820,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                 debug!("err_out_of_scope: self.body.is_generator = {:?}",
                        self.body.is_generator);
                 let maybe_borrow_across_yield = if self.body.is_generator {
-                    let body_extent = region::CodeExtent::Misc(self.body.id().node_id);
+                    let body_extent = region::CodeExtent::Misc(self.body.value.hir_id.local_id);
                     debug!("err_out_of_scope: body_extent = {:?}", body_extent);
                     debug!("err_out_of_scope: super_scope = {:?}", super_scope);
                     debug!("err_out_of_scope: sub_scope = {:?}", sub_scope);
@@ -844,7 +846,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                                 // block remainder that starts with
                                 // `let a`) for a yield. We can cite
                                 // that for the user.
-                                self.tcx.yield_in_extent(value_extent, &mut FxHashMap())
+                                self.region_maps.yield_in_scope(value_extent)
                             } else {
                                 None
                             }
@@ -966,8 +968,14 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                     }
                 }
 
-                if let Some(_) = statement_scope_span(self.tcx, super_scope) {
-                    db.note("consider using a `let` binding to increase its lifetime");
+                if let ty::ReScope(scope) = *super_scope {
+                    let node_id = scope.node_id(self.tcx, &self.region_maps);
+                    match self.tcx.hir.find(node_id) {
+                        Some(hir_map::NodeStmt(_)) => {
+                            db.note("consider using a `let` binding to increase its lifetime");
+                        }
+                        _ => {}
+                    }
                 }
 
                 db.emit();
@@ -1386,18 +1394,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
     }
 }
 
-fn statement_scope_span(tcx: TyCtxt, region: ty::Region) -> Option<Span> {
-    match *region {
-        ty::ReScope(scope) => {
-            match tcx.hir.find(scope.node_id()) {
-                Some(hir_map::NodeStmt(stmt)) => Some(stmt.span),
-                _ => None
-            }
-        }
-        _ => None
-    }
-}
-
 impl BitwiseOperator for LoanDataFlowOperator {
     #[inline]
     fn join(&self, succ: usize, pred: usize) -> usize {
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index 79a4a4f9f4d5b..7915eccbf7445 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -485,8 +485,7 @@ impl<'a, 'tcx> MoveData<'tcx> {
                 LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
                     let kill_scope = path.loan_path.kill_scope(bccx);
                     let path = *self.path_map.borrow().get(&path.loan_path).unwrap();
-                    self.kill_moves(path,
-                                    bccx.tcx.hir.node_to_hir_id(kill_scope.node_id()).local_id,
+                    self.kill_moves(path, kill_scope.item_local_id(),
                                     KillFrom::ScopeEnd, dfcx_moves);
                 }
                 LpExtend(..) => {}
@@ -501,8 +500,7 @@ impl<'a, 'tcx> MoveData<'tcx> {
                 LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
                     let kill_scope = lp.kill_scope(bccx);
                     dfcx_assign.add_kill(KillFrom::ScopeEnd,
-                                         bccx.tcx.hir.node_to_hir_id(kill_scope.node_id())
-                                            .local_id,
+                                         kill_scope.item_local_id(),
                                          assignment_index);
                 }
                 LpExtend(..) => {
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index b187cdaa480ed..247f51b1da443 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -50,7 +50,7 @@ struct Env<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
 }
 
 struct RH<'a> {
-    id: ast::NodeId,
+    id: hir::ItemLocalId,
     sub: &'a [RH<'a>],
 }
 
@@ -157,7 +157,7 @@ fn test_env<F>(source_string: &str,
                              "test_crate",
                              |tcx| {
         tcx.infer_ctxt().enter(|infcx| {
-            let mut region_maps = RegionMaps::new();
+            let mut region_maps = RegionMaps::default();
             body(Env {
                 infcx: &infcx,
                 region_maps: &mut region_maps,
@@ -188,21 +188,19 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
         // creates a region hierarchy where 1 is root, 10 and 11 are
         // children of 1, etc
 
-        let node = ast::NodeId::from_u32;
-        let dscope = CodeExtent::DestructionScope(node(1));
+        let dscope = CodeExtent::DestructionScope(hir::ItemLocalId(1));
         self.region_maps.record_code_extent(dscope, None);
         self.create_region_hierarchy(&RH {
-                                         id: node(1),
-                                         sub: &[RH {
-                                                    id: node(10),
-                                                    sub: &[],
-                                                },
-                                                RH {
-                                                    id: node(11),
-                                                    sub: &[],
-                                                }],
-                                     },
-                                     dscope);
+            id: hir::ItemLocalId(1),
+            sub: &[RH {
+                id: hir::ItemLocalId(10),
+                sub: &[],
+            },
+            RH {
+                id: hir::ItemLocalId(11),
+                sub: &[],
+            }],
+        }, dscope);
     }
 
     #[allow(dead_code)] // this seems like it could be useful, even if we don't use it now
@@ -335,7 +333,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
     }
 
     pub fn t_rptr_scope(&self, id: u32) -> Ty<'tcx> {
-        let r = ty::ReScope(CodeExtent::Misc(ast::NodeId::from_u32(id)));
+        let r = ty::ReScope(CodeExtent::Misc(hir::ItemLocalId(id)));
         self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
     }
 
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 0fe30dcabb00d..52b645638b86f 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -854,7 +854,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
             let local_id = cfg.graph.node_data(idx).id();
             if local_id != hir::DUMMY_ITEM_LOCAL_ID {
                 let node_id = cx.tcx.hir.hir_to_node_id(hir::HirId {
-                    owner: cx.tcx.closure_base_def_id(cfg.owner_def_id).index,
+                    owner: body.value.hir_id.owner,
                     local_id
                 });
                 let self_recursive = match method {
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index fb345e944969a..fc6eca466a811 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -202,7 +202,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub fn schedule_drop_for_binding(&mut self, var: NodeId, span: Span) {
         let local_id = self.var_indices[&var];
         let var_ty = self.local_decls[local_id].ty;
-        let extent = self.hir.region_maps.var_scope(var);
+        let hir_id = self.hir.tcx().hir.node_to_hir_id(var);
+        let extent = self.hir.region_maps.var_scope(hir_id.local_id);
         self.schedule_drop(span, extent, &Lvalue::Local(local_id), var_ty);
     }
 
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 904e30a01eba6..5cced32f7e69b 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -355,8 +355,8 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
         arguments.len(),
         return_ty);
 
-    let call_site_extent = CodeExtent::CallSiteScope(body.id());
-    let arg_extent = CodeExtent::ParameterScope(body.id());
+    let call_site_extent = CodeExtent::CallSiteScope(body.value.hir_id.local_id);
+    let arg_extent = CodeExtent::ParameterScope(body.value.hir_id.local_id);
     let mut block = START_BLOCK;
     let source_info = builder.source_info(span);
     unpack!(block = builder.in_scope((call_site_extent, source_info), block, |builder| {
diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs
index d38c72c37e80f..8a87751d846c8 100644
--- a/src/librustc_mir/hair/cx/block.rs
+++ b/src/librustc_mir/hair/cx/block.rs
@@ -13,7 +13,6 @@ use hair::cx::Cx;
 use hair::cx::to_ref::ToRef;
 use rustc::middle::region::{BlockRemainder, CodeExtent};
 use rustc::hir;
-use syntax::ast;
 
 impl<'tcx> Mirror<'tcx> for &'tcx hir::Block {
     type Output = Block<'tcx>;
@@ -21,11 +20,11 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block {
     fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Block<'tcx> {
         // We have to eagerly translate the "spine" of the statements
         // in order to get the lexical scoping correctly.
-        let stmts = mirror_stmts(cx, self.id, &*self.stmts);
-        let opt_destruction_extent = cx.region_maps.opt_destruction_extent(self.id);
+        let stmts = mirror_stmts(cx, self.hir_id.local_id, &*self.stmts);
+        let opt_destruction_extent = cx.region_maps.opt_destruction_extent(self.hir_id.local_id);
         Block {
             targeted_by_break: self.targeted_by_break,
-            extent: CodeExtent::Misc(self.id),
+            extent: CodeExtent::Misc(self.hir_id.local_id),
             opt_destruction_extent,
             span: self.span,
             stmts,
@@ -35,24 +34,25 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block {
 }
 
 fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
-                                block_id: ast::NodeId,
+                                block_id: hir::ItemLocalId,
                                 stmts: &'tcx [hir::Stmt])
                                 -> Vec<StmtRef<'tcx>> {
     let mut result = vec![];
     for (index, stmt) in stmts.iter().enumerate() {
-        let opt_dxn_ext = cx.region_maps.opt_destruction_extent(stmt.node.id());
+        let hir_id = cx.tcx.hir.node_to_hir_id(stmt.node.id());
+        let opt_dxn_ext = cx.region_maps.opt_destruction_extent(hir_id.local_id);
         match stmt.node {
-            hir::StmtExpr(ref expr, id) |
-            hir::StmtSemi(ref expr, id) => {
+            hir::StmtExpr(ref expr, _) |
+            hir::StmtSemi(ref expr, _) => {
                 result.push(StmtRef::Mirror(Box::new(Stmt {
                     kind: StmtKind::Expr {
-                        scope: CodeExtent::Misc(id),
+                        scope: CodeExtent::Misc(hir_id.local_id),
                         expr: expr.to_ref(),
                     },
                     opt_destruction_extent: opt_dxn_ext,
                 })))
             }
-            hir::StmtDecl(ref decl, id) => {
+            hir::StmtDecl(ref decl, _) => {
                 match decl.node {
                     hir::DeclItem(..) => {
                         // ignore for purposes of the MIR
@@ -70,7 +70,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         result.push(StmtRef::Mirror(Box::new(Stmt {
                             kind: StmtKind::Let {
                                 remainder_scope: remainder_extent,
-                                init_scope: CodeExtent::Misc(id),
+                                init_scope: CodeExtent::Misc(hir_id.local_id),
                                 pattern,
                                 initializer: local.init.to_ref(),
                             },
@@ -88,7 +88,7 @@ pub fn to_expr_ref<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                    block: &'tcx hir::Block)
                                    -> ExprRef<'tcx> {
     let block_ty = cx.tables().node_id_to_type(block.hir_id);
-    let temp_lifetime = cx.region_maps.temporary_scope(block.id);
+    let temp_lifetime = cx.region_maps.temporary_scope(block.hir_id.local_id);
     let expr = Expr {
         ty: block_ty,
         temp_lifetime,
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 553da2c978fe7..a877c61a47a91 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -25,8 +25,8 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
     type Output = Expr<'tcx>;
 
     fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
-        let temp_lifetime = cx.region_maps.temporary_scope(self.id);
-        let expr_extent = CodeExtent::Misc(self.id);
+        let temp_lifetime = cx.region_maps.temporary_scope(self.hir_id.local_id);
+        let expr_extent = CodeExtent::Misc(self.hir_id.local_id);
 
         debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
 
@@ -52,7 +52,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
         };
 
         // Finally, create a destruction scope, if any.
-        if let Some(extent) = cx.region_maps.opt_destruction_extent(self.id) {
+        if let Some(extent) = cx.region_maps.opt_destruction_extent(self.hir_id.local_id) {
             expr = Expr {
                 temp_lifetime,
                 ty: expr.ty,
@@ -125,7 +125,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             // Convert this to a suitable `&foo` and
             // then an unsafe coercion. Limit the region to be just this
             // expression.
-            let region = ty::ReScope(CodeExtent::Misc(hir_expr.id));
+            let region = ty::ReScope(CodeExtent::Misc(hir_expr.hir_id.local_id));
             let region = cx.tcx.mk_region(region);
             expr = Expr {
                 temp_lifetime,
@@ -160,7 +160,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                           expr: &'tcx hir::Expr)
                                           -> Expr<'tcx> {
     let expr_ty = cx.tables().expr_ty(expr);
-    let temp_lifetime = cx.region_maps.temporary_scope(expr.id);
+    let temp_lifetime = cx.region_maps.temporary_scope(expr.hir_id.local_id);
 
     let kind = match expr.node {
         // Here comes the interesting stuff:
@@ -487,7 +487,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             match dest.target_id {
                 hir::ScopeTarget::Block(target_id) |
                 hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(target_id)) => ExprKind::Break {
-                    label: CodeExtent::Misc(target_id),
+                    label: CodeExtent::Misc(cx.tcx.hir.node_to_hir_id(target_id).local_id),
                     value: value.to_ref(),
                 },
                 hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
@@ -498,7 +498,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             match dest.target_id {
                 hir::ScopeTarget::Block(_) => bug!("cannot continue to blocks"),
                 hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(loop_id)) => ExprKind::Continue {
-                    label: CodeExtent::Misc(loop_id),
+                    label: CodeExtent::Misc(cx.tcx.hir.node_to_hir_id(loop_id).local_id),
                 },
                 hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
                     bug!("invalid loop id for continue: {}", err)
@@ -585,7 +585,7 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                  expr: &hir::Expr,
                                  custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>)
                                  -> Expr<'tcx> {
-    let temp_lifetime = cx.region_maps.temporary_scope(expr.id);
+    let temp_lifetime = cx.region_maps.temporary_scope(expr.hir_id.local_id);
     let (def_id, substs) = custom_callee.unwrap_or_else(|| {
         (cx.tables().type_dependent_defs()[expr.hir_id].def_id(),
          cx.tables().node_substs(expr.hir_id))
@@ -676,7 +676,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                expr: &'tcx hir::Expr,
                                def: Def)
                                -> ExprKind<'tcx> {
-    let temp_lifetime = cx.region_maps.temporary_scope(expr.id);
+    let temp_lifetime = cx.region_maps.temporary_scope(expr.hir_id.local_id);
 
     match def {
         Def::Local(def_id) => {
@@ -867,7 +867,7 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
     // construct the complete expression `foo()` for the overloaded call,
     // which will yield the &T type
-    let temp_lifetime = cx.region_maps.temporary_scope(expr.id);
+    let temp_lifetime = cx.region_maps.temporary_scope(expr.hir_id.local_id);
     let fun = method_callee(cx, expr, custom_callee);
     let ref_expr = Expr {
         temp_lifetime,
@@ -896,7 +896,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         closure_expr_id: cx.tcx.hir.local_def_id(closure_expr.id).index,
     };
     let upvar_capture = cx.tables().upvar_capture(upvar_id);
-    let temp_lifetime = cx.region_maps.temporary_scope(closure_expr.id);
+    let temp_lifetime = cx.region_maps.temporary_scope(closure_expr.hir_id.local_id);
     let var_ty = cx.tables()
                    .node_id_to_type(cx.tcx.hir.node_to_hir_id(var_node_id));
     let captured_var = Expr {
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index bf134f9547d38..a4bbedfb26b38 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -340,7 +340,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             // region obligations that get overlooked.  The right
             // thing to do is the code below. But we keep this old
             // pass around temporarily.
-            let region_maps = RegionMaps::new();
+            let region_maps = RegionMaps::default();
             let mut free_regions = FreeRegionMap::new();
             free_regions.relate_free_regions_from_predicates(&param_env.caller_bounds);
             infcx.resolve_regions_and_report_errors(impl_m.def_id, &region_maps, &free_regions);
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 72ff9eb6f5b0d..fd7dd052cd16d 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -114,7 +114,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
             return Err(ErrorReported);
         }
 
-        let region_maps = RegionMaps::new();
+        let region_maps = RegionMaps::default();
         let free_regions = FreeRegionMap::new();
         infcx.resolve_regions_and_report_errors(drop_impl_did, &region_maps, &free_regions);
         Ok(())
diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs
index 46948b687d26d..60762134f0ffd 100644
--- a/src/librustc_typeck/check/generator_interior.rs
+++ b/src/librustc_typeck/check/generator_interior.rs
@@ -18,15 +18,12 @@ use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::{self, Body, Pat, PatKind, Expr};
 use rustc::middle::region::{RegionMaps, CodeExtent};
 use rustc::ty::Ty;
-use syntax::ast::NodeId;
-use syntax::codemap::Span;
 use std::rc::Rc;
 use super::FnCtxt;
 use util::nodemap::FxHashMap;
 
 struct InteriorVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
-    cache: FxHashMap<NodeId, Option<Span>>,
     types: FxHashMap<Ty<'tcx>, usize>,
     region_maps: Rc<RegionMaps>,
 }
@@ -36,7 +33,7 @@ impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> {
         use syntax_pos::DUMMY_SP;
 
         let live_across_yield = scope.map_or(Some(DUMMY_SP), |s| {
-            self.fcx.tcx.yield_in_extent(s, &mut self.cache)
+            self.region_maps.yield_in_scope(s)
         });
 
         if let Some(span) = live_across_yield {
@@ -62,7 +59,6 @@ pub fn resolve_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
     let mut visitor = InteriorVisitor {
         fcx,
         types: FxHashMap(),
-        cache: FxHashMap(),
         region_maps: fcx.tcx.region_maps(def_id),
     };
     intravisit::walk_body(&mut visitor, body);
@@ -97,7 +93,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'gcx, 'tcx> {
 
     fn visit_pat(&mut self, pat: &'tcx Pat) {
         if let PatKind::Binding(..) = pat.node {
-            let scope = self.region_maps.var_scope(pat.id);
+            let scope = self.region_maps.var_scope(pat.hir_id.local_id);
             let ty = self.fcx.tables.borrow().pat_ty(pat);
             self.record(ty, Some(scope), None);
         }
@@ -106,7 +102,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'gcx, 'tcx> {
     }
 
     fn visit_expr(&mut self, expr: &'tcx Expr) {
-        let scope = self.region_maps.temporary_scope(expr.id);
+        let scope = self.region_maps.temporary_scope(expr.hir_id.local_id);
         let ty = self.fcx.tables.borrow().expr_ty_adjusted(expr);
         self.record(ty, scope, Some(expr));
 
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index bd362c3535373..2fa80a10d12e4 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -606,8 +606,9 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
         let tcx = infcx.tcx;
         let item_id = tcx.hir.as_local_node_id(def_id);
         let body_id = item_id.and_then(|id| tcx.hir.maybe_body_owned_by(id));
-        let implicit_region_bound = body_id.map(|body| {
-            tcx.mk_region(ty::ReScope(CodeExtent::CallSiteScope(body)))
+        let implicit_region_bound = body_id.map(|body_id| {
+            let body = tcx.hir.body(body_id);
+            tcx.mk_region(ty::ReScope(CodeExtent::CallSiteScope(body.value.hir_id.local_id)))
         });
 
         Inherited {
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 377908b1ab9d4..0cd38a49adef2 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -305,7 +305,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
         let body_id = body.id();
 
-        let call_site = CodeExtent::CallSiteScope(body_id);
+        let call_site = CodeExtent::CallSiteScope(body.value.hir_id.local_id);
         let old_call_site_scope = self.set_call_site_scope(Some(call_site));
 
         let fn_sig = {
@@ -330,7 +330,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
         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(CodeExtent::Misc(body_id.node_id), &body.arguments);
+        self.link_fn_args(CodeExtent::Misc(body.value.hir_id.local_id), &body.arguments);
         self.visit_body(body);
         self.visit_region_obligations(body_id.node_id);
 
@@ -610,11 +610,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
             // that the lifetime of any regions that appear in a
             // variable's type enclose at least the variable's scope.
 
-            let var_scope = self.region_maps.var_scope(id);
+            let hir_id = self.tcx.hir.node_to_hir_id(id);
+            let var_scope = self.region_maps.var_scope(hir_id.local_id);
             let var_region = self.tcx.mk_region(ty::ReScope(var_scope));
 
             let origin = infer::BindingTypeIsNotValidAtDecl(span);
-            let hir_id = self.tcx.hir.node_to_hir_id(id);
             self.type_of_node_must_outlive(origin, hir_id, var_region);
 
             let typ = self.resolve_node_type(hir_id);
@@ -668,7 +668,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> {
         // scope of that expression. This also guarantees basic WF.
         let expr_ty = self.resolve_node_type(expr.hir_id);
         // the region corresponding to this expression
-        let expr_region = self.tcx.node_scope_region(expr.id);
+        let expr_region = self.tcx.mk_region(ty::ReScope(CodeExtent::Misc(expr.hir_id.local_id)));
         self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span),
                                expr_ty, expr_region);
 
@@ -950,7 +950,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         // call occurs.
         //
         // FIXME(#6268) to support nested method calls, should be callee_id
-        let callee_scope = CodeExtent::Misc(call_expr.id);
+        let callee_scope = CodeExtent::Misc(call_expr.hir_id.local_id);
         let callee_region = self.tcx.mk_region(ty::ReScope(callee_scope));
 
         debug!("callee_region={:?}", callee_region);
@@ -1002,7 +1002,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         // expression.
         self.check_safety_of_rvalue_destructor_if_necessary(cmt.clone(), expr.span);
 
-        let expr_region = self.tcx.node_scope_region(expr.id);
+        let expr_region = self.tcx.mk_region(ty::ReScope(CodeExtent::Misc(expr.hir_id.local_id)));
         for adjustment in adjustments {
             debug!("constrain_adjustments: adjustment={:?}, cmt={:?}",
                    adjustment, cmt);
@@ -1095,7 +1095,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         debug!("constrain_index(index_expr=?, indexed_ty={}",
                self.ty_to_string(indexed_ty));
 
-        let r_index_expr = ty::ReScope(CodeExtent::Misc(index_expr.id));
+        let r_index_expr = ty::ReScope(CodeExtent::Misc(index_expr.hir_id.local_id));
         if let ty::TyRef(r_ptr, mt) = indexed_ty.sty {
             match mt.ty.sty {
                 ty::TySlice(_) | ty::TyStr => {
@@ -1232,7 +1232,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
             }
 
             adjustment::AutoBorrow::RawPtr(m) => {
-                let r = self.tcx.node_scope_region(expr.id);
+                let r = self.tcx.mk_region(ty::ReScope(CodeExtent::Misc(expr.hir_id.local_id)));
                 self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt);
             }
         }
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
index 9305eff143652..9cf15e2145d36 100644
--- a/src/librustc_typeck/coherence/builtin.rs
+++ b/src/librustc_typeck/coherence/builtin.rs
@@ -390,7 +390,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
 
         // Finally, resolve all regions.
-        let region_maps = RegionMaps::new();
+        let region_maps = RegionMaps::default();
         let mut free_regions = FreeRegionMap::new();
         free_regions.relate_free_regions_from_predicates(&param_env.caller_bounds);
         infcx.resolve_regions_and_report_errors(impl_did, &region_maps, &free_regions);
diff --git a/src/test/mir-opt/end_region_1.rs b/src/test/mir-opt/end_region_1.rs
index 55dac4440275f..7be677c184b73 100644
--- a/src/test/mir-opt/end_region_1.rs
+++ b/src/test/mir-opt/end_region_1.rs
@@ -22,16 +22,16 @@ fn main() {
 // START rustc.node4.SimplifyCfg-qualify-consts.after.mir
 //     let mut _0: ();
 //     let _1: i32;
-//     let _2: &'6_1rce i32;
+//     let _2: &'10_1rce i32;
 //
 //     bb0: {
 //         StorageLive(_1);
 //         _1 = const 3i32;
 //         StorageLive(_2);
-//         _2 = &'6_1rce _1;
+//         _2 = &'10_1rce _1;
 //         _0 = ();
 //         StorageDead(_2);
-//         EndRegion('6_1rce);
+//         EndRegion('10_1rce);
 //         StorageDead(_1);
 //         return;
 //     }
diff --git a/src/test/mir-opt/end_region_2.rs b/src/test/mir-opt/end_region_2.rs
index a1386ec47a13b..2cb9b38e7bb94 100644
--- a/src/test/mir-opt/end_region_2.rs
+++ b/src/test/mir-opt/end_region_2.rs
@@ -27,8 +27,8 @@ fn main() {
 // START rustc.node4.SimplifyCfg-qualify-consts.after.mir
 //     let mut _0: ();
 //     let _2: bool;
-//     let _3: &'7_1rce bool;
-//     let _7: &'7_3rce bool;
+//     let _3: &'23_1rce bool;
+//     let _7: &'23_3rce bool;
 //     let mut _4: ();
 //     let mut _5: bool;
 //     bb0: {
@@ -38,7 +38,7 @@ fn main() {
 //         StorageLive(_2);
 //         _2 = const true;
 //         StorageLive(_3);
-//         _3 = &'7_1rce _2;
+//         _3 = &'23_1rce _2;
 //         StorageLive(_5);
 //         _5 = _2;
 //         switchInt(_5) -> [0u8: bb3, otherwise: bb2];
@@ -47,19 +47,19 @@ fn main() {
 //         _0 = ();
 //         StorageDead(_5);
 //         StorageDead(_3);
-//         EndRegion('7_1rce);
+//         EndRegion('23_1rce);
 //         StorageDead(_2);
 //         return;
 //     }
 //     bb3: {
 //         StorageDead(_5);
 //         StorageLive(_7);
-//         _7 = &'7_3rce _2;
+//         _7 = &'23_3rce _2;
 //         _1 = ();
 //         StorageDead(_7);
-//         EndRegion('7_3rce);
+//         EndRegion('23_3rce);
 //         StorageDead(_3);
-//         EndRegion('7_1rce);
+//         EndRegion('23_1rce);
 //         StorageDead(_2);
 //         goto -> bb1;
 //     }
diff --git a/src/test/mir-opt/end_region_3.rs b/src/test/mir-opt/end_region_3.rs
index b3d2809e76ceb..001bb9c1a0284 100644
--- a/src/test/mir-opt/end_region_3.rs
+++ b/src/test/mir-opt/end_region_3.rs
@@ -28,8 +28,8 @@ fn main() {
 // START rustc.node4.SimplifyCfg-qualify-consts.after.mir
 //     let mut _0: ();
 //     let mut _1: bool;
-//     let _3: &'9_1rce bool;
-//     let _7: &'9_3rce bool;
+//     let _3: &'26_1rce bool;
+//     let _7: &'26_3rce bool;
 //     let mut _2: ();
 //     let mut _4: ();
 //     let mut _5: bool;
@@ -41,7 +41,7 @@ fn main() {
 //     bb1: {
 //         _1 = const true;
 //         StorageLive(_3);
-//         _3 = &'9_1rce _1;
+//         _3 = &'26_1rce _1;
 //         StorageLive(_5);
 //         _5 = _1;
 //         switchInt(_5) -> [0u8: bb3, otherwise: bb2];
@@ -50,7 +50,7 @@ fn main() {
 //         _0 = ();
 //         StorageDead(_5);
 //         StorageDead(_3);
-//         EndRegion('9_1rce);
+//         EndRegion('26_1rce);
 //         StorageDead(_1);
 //         return;
 //     }
@@ -58,12 +58,12 @@ fn main() {
 //         _4 = ();
 //         StorageDead(_5);
 //         StorageLive(_7);
-//         _7 = &'9_3rce _1;
+//         _7 = &'26_3rce _1;
 //         _2 = ();
 //         StorageDead(_7);
-//         EndRegion('9_3rce);
+//         EndRegion('26_3rce);
 //         StorageDead(_3);
-//         EndRegion('9_1rce);
+//         EndRegion('26_1rce);
 //         goto -> bb1;
 //     }
 // END rustc.node4.SimplifyCfg-qualify-consts.after.mir
diff --git a/src/test/mir-opt/end_region_4.rs b/src/test/mir-opt/end_region_4.rs
index 0b34231b4eec6..8c854ce87a2c6 100644
--- a/src/test/mir-opt/end_region_4.rs
+++ b/src/test/mir-opt/end_region_4.rs
@@ -33,8 +33,8 @@ fn foo(i: i32) {
 //     let mut _0: ();
 //     let _1: D;
 //     let _2: i32;
-//     let _3: &'6_2rce i32;
-//     let _6: &'6_4rce i32;
+//     let _3: &'26_2rce i32;
+//     let _6: &'26_4rce i32;
 //     let mut _4: ();
 //     let mut _5: i32;
 //     bb0: {
@@ -43,7 +43,7 @@ fn foo(i: i32) {
 //         StorageLive(_2);
 //         _2 = const 0i32;
 //         StorageLive(_3);
-//         _3 = &'6_2rce _2;
+//         _3 = &'26_2rce _2;
 //         StorageLive(_5);
 //         _5 = (*_3);
 //         _4 = const foo(_5) -> [return: bb1, unwind: bb3];
@@ -51,12 +51,12 @@ fn foo(i: i32) {
 //     bb1: {
 //         StorageDead(_5);
 //         StorageLive(_6);
-//         _6 = &'6_4rce _2;
+//         _6 = &'26_4rce _2;
 //         _0 = ();
 //         StorageDead(_6);
-//         EndRegion('6_4rce);
+//         EndRegion('26_4rce);
 //         StorageDead(_3);
-//         EndRegion('6_2rce);
+//         EndRegion('26_2rce);
 //         StorageDead(_2);
 //         drop(_1) -> bb4;
 //     }
@@ -64,7 +64,7 @@ fn foo(i: i32) {
 //         resume;
 //     }
 //     bb3: {
-//         EndRegion('6_2rce);
+//         EndRegion('26_2rce);
 //         drop(_1) -> bb2;
 //     }
 //     bb4: {
diff --git a/src/test/mir-opt/end_region_5.rs b/src/test/mir-opt/end_region_5.rs
index e51bb9350db60..ae1b4e2e83abb 100644
--- a/src/test/mir-opt/end_region_5.rs
+++ b/src/test/mir-opt/end_region_5.rs
@@ -31,21 +31,21 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //     let mut _0: ();
 //     let _1: D;
 //     let mut _2: ();
-//     let mut _3: [closure@NodeId(18) d:&'19mce D];
-//     let mut _4: &'19mce D;
+//     let mut _3: [closure@NodeId(18) d:&'14mce D];
+//     let mut _4: &'14mce D;
 //     bb0: {
 //         StorageLive(_1);
 //         _1 = D::{{constructor}}(const 0i32,);
 //         StorageLive(_3);
 //         StorageLive(_4);
-//         _4 = &'19mce _1;
+//         _4 = &'14mce _1;
 //         _3 = [closure@NodeId(18)] { d: _4 };
 //         StorageDead(_4);
 //         _2 = const foo(_3) -> [return: bb1, unwind: bb3];
 //     }
 //     bb1: {
 //         StorageDead(_3);
-//         EndRegion('19mce);
+//         EndRegion('14mce);
 //         _0 = ();
 //         drop(_1) -> bb4;
 //     }
@@ -53,7 +53,7 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //         resume;
 //     }
 //     bb3: {
-//         EndRegion('19mce);
+//         EndRegion('14mce);
 //         drop(_1) -> bb2;
 //     }
 //     bb4: {
@@ -64,13 +64,13 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // END rustc.node4.SimplifyCfg-qualify-consts.after.mir
 
 // START rustc.node18.SimplifyCfg-qualify-consts.after.mir
-// fn main::{{closure}}(_1: [closure@NodeId(18) d:&'19mce D]) -> i32 {
+// fn main::{{closure}}(_1: [closure@NodeId(18) d:&'14mce D]) -> i32 {
 //    let mut _0: i32;
 //    let mut _2: i32;
 //
 //    bb0: {
 //        StorageLive(_2);
-//        _2 = ((*(_1.0: &'19mce D)).0: i32);
+//        _2 = ((*(_1.0: &'14mce D)).0: i32);
 //        _0 = _2;
 //        StorageDead(_2);
 //        return;
diff --git a/src/test/mir-opt/end_region_6.rs b/src/test/mir-opt/end_region_6.rs
index c55e6d105cbdc..8054b64400669 100644
--- a/src/test/mir-opt/end_region_6.rs
+++ b/src/test/mir-opt/end_region_6.rs
@@ -31,21 +31,21 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //     let mut _0: ();
 //     let _1: D;
 //     let mut _2: ();
-//     let mut _3: [closure@NodeId(22) d:&'23mce D];
-//     let mut _4: &'23mce D;
+//     let mut _3: [closure@NodeId(22) d:&'19mce D];
+//     let mut _4: &'19mce D;
 //     bb0: {
 //         StorageLive(_1);
 //         _1 = D::{{constructor}}(const 0i32,);
 //         StorageLive(_3);
 //         StorageLive(_4);
-//         _4 = &'23mce _1;
+//         _4 = &'19mce _1;
 //         _3 = [closure@NodeId(22)] { d: _4 };
 //         StorageDead(_4);
 //         _2 = const foo(_3) -> [return: bb1, unwind: bb3];
 //     }
 //     bb1: {
 //         StorageDead(_3);
-//         EndRegion('23mce);
+//         EndRegion('19mce);
 //         _0 = ();
 //         drop(_1) -> bb4;
 //     }
@@ -53,7 +53,7 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //         resume;
 //     }
 //     bb3: {
-//         EndRegion('23mce);
+//         EndRegion('19mce);
 //         drop(_1) -> bb2;
 //     }
 //     bb4: {
@@ -63,20 +63,20 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // END rustc.node4.SimplifyCfg-qualify-consts.after.mir
 
 // START rustc.node22.SimplifyCfg-qualify-consts.after.mir
-// fn main::{{closure}}(_1: [closure@NodeId(22) d:&'23mce D]) -> i32 {
+// fn main::{{closure}}(_1: [closure@NodeId(22) d:&'19mce D]) -> i32 {
 //     let mut _0: i32;
-//     let _2: &'14_0rce D;
+//     let _2: &'15_0rce D;
 //     let mut _3: i32;
 //
 //     bb0: {
 //         StorageLive(_2);
-//         _2 = &'14_0rce (*(_1.0: &'23mce D));
+//         _2 = &'15_0rce (*(_1.0: &'19mce D));
 //         StorageLive(_3);
 //         _3 = ((*_2).0: i32);
 //         _0 = _3;
 //         StorageDead(_3);
 //         StorageDead(_2);
-//         EndRegion('14_0rce);
+//         EndRegion('15_0rce);
 //         return;
 //     }
 // END rustc.node22.SimplifyCfg-qualify-consts.after.mir
diff --git a/src/test/mir-opt/end_region_7.rs b/src/test/mir-opt/end_region_7.rs
index 9c8e3ec08d498..d68439087615b 100644
--- a/src/test/mir-opt/end_region_7.rs
+++ b/src/test/mir-opt/end_region_7.rs
@@ -74,18 +74,18 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // START rustc.node22.SimplifyCfg-qualify-consts.after.mir
 // fn main::{{closure}}(_1: [closure@NodeId(22) d:D]) -> i32 {
 //     let mut _0: i32;
-//     let _2: &'14_0rce D;
+//     let _2: &'15_0rce D;
 //     let mut _3: i32;
 //
 //     bb0: {
 //         StorageLive(_2);
-//         _2 = &'14_0rce (_1.0: D);
+//         _2 = &'15_0rce (_1.0: D);
 //         StorageLive(_3);
 //         _3 = ((*_2).0: i32);
 //         _0 = _3;
 //         StorageDead(_3);
 //         StorageDead(_2);
-//         EndRegion('14_0rce);
+//         EndRegion('15_0rce);
 //         drop(_1) -> bb1;
 //     }
 //     bb1: {
diff --git a/src/test/mir-opt/end_region_8.rs b/src/test/mir-opt/end_region_8.rs
index b4dbec5cd2dd7..8d7050941e7eb 100644
--- a/src/test/mir-opt/end_region_8.rs
+++ b/src/test/mir-opt/end_region_8.rs
@@ -31,15 +31,15 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // fn main() -> () {
 //    let mut _0: ();
 //    let _1: D;
-//    let _2: &'6_1rce D;
+//    let _2: &'21_1rce D;
 //    let mut _3: ();
-//    let mut _4: [closure@NodeId(22) r:&'6_1rce D];
-//    let mut _5: &'6_1rce D;
+//    let mut _4: [closure@NodeId(22) r:&'21_1rce D];
+//    let mut _5: &'21_1rce D;
 //    bb0: {
 //        StorageLive(_1);
 //        _1 = D::{{constructor}}(const 0i32,);
 //        StorageLive(_2);
-//        _2 = &'6_1rce _1;
+//        _2 = &'21_1rce _1;
 //        StorageLive(_4);
 //        StorageLive(_5);
 //        _5 = _2;
@@ -51,14 +51,14 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 //        StorageDead(_4);
 //        _0 = ();
 //        StorageDead(_2);
-//        EndRegion('6_1rce);
+//        EndRegion('21_1rce);
 //        drop(_1) -> bb4;
 //    }
 //    bb2: {
 //        resume;
 //    }
 //    bb3: {
-//        EndRegion('6_1rce);
+//        EndRegion('21_1rce);
 //        drop(_1) -> bb2;
 //    }
 //    bb4: {
@@ -69,13 +69,13 @@ fn foo<F>(f: F) where F: FnOnce() -> i32 {
 // END rustc.node4.SimplifyCfg-qualify-consts.after.mir
 
 // START rustc.node22.SimplifyCfg-qualify-consts.after.mir
-// fn main::{{closure}}(_1: [closure@NodeId(22) r:&'6_1rce D]) -> i32 {
+// fn main::{{closure}}(_1: [closure@NodeId(22) r:&'21_1rce D]) -> i32 {
 //     let mut _0: i32;
 //     let mut _2: i32;
 //
 //     bb0: {
 //         StorageLive(_2);
-//         _2 = ((*(_1.0: &'6_1rce D)).0: i32);
+//         _2 = ((*(_1.0: &'21_1rce D)).0: i32);
 //         _0 = _2;
 //         StorageDead(_2);
 //         return;
diff --git a/src/test/mir-opt/validate_1.rs b/src/test/mir-opt/validate_1.rs
index 677c92ea71b7a..9c528da8b348d 100644
--- a/src/test/mir-opt/validate_1.rs
+++ b/src/test/mir-opt/validate_1.rs
@@ -37,19 +37,19 @@ fn main() {
 // START rustc.node23.EraseRegions.after.mir
 // fn main() -> () {
 //     bb0: {
-//         Validate(Suspend(ReScope(Misc(NodeId(34)))), [_1: i32]);
+//         Validate(Suspend(ReScope(Misc(ItemLocalId(10)))), [_1: i32]);
 //         _6 = &ReErased mut _1;
-//         Validate(Acquire, [(*_6): i32/ReScope(Misc(NodeId(34)))]);
-//         Validate(Suspend(ReScope(Misc(NodeId(34)))), [(*_6): i32/ReScope(Misc(NodeId(34)))]);
+//         Validate(Acquire, [(*_6): i32/ReScope(Misc(ItemLocalId(10)))]);
+//         Validate(Suspend(ReScope(Misc(ItemLocalId(10)))), [(*_6): i32/ReScope(Misc(ItemLocalId(10)))]);
 //         _5 = &ReErased mut (*_6);
-//         Validate(Acquire, [(*_5): i32/ReScope(Misc(NodeId(34)))]);
-//         Validate(Release, [_2: (), _3: &ReScope(Misc(NodeId(34))) Test, _5: &ReScope(Misc(NodeId(34))) mut i32]);
+//         Validate(Acquire, [(*_5): i32/ReScope(Misc(ItemLocalId(10)))]);
+//         Validate(Release, [_2: (), _3: &ReScope(Misc(ItemLocalId(10))) Test, _5: &ReScope(Misc(ItemLocalId(10))) mut i32]);
 //         _2 = const Test::foo(_3, _5) -> bb1;
 //     }
 //
 //     bb1: {
 //         Validate(Acquire, [_2: ()]);
-//         EndRegion(ReScope(Misc(NodeId(34))));
+//         EndRegion(ReScope(Misc(ItemLocalId(10))));
 //         return;
 //     }
 // }
@@ -61,15 +61,15 @@ fn main() {
 //         StorageLive(_3);
 //         _3 = _2;
 //         StorageLive(_4);
-//         Validate(Suspend(ReScope(Remainder(BlockRemainder { block: NodeId(41), first_statement_index: 0 }))), [(*_3): i32]);
+//         Validate(Suspend(ReScope(Remainder(BlockRemainder { block: ItemLocalId(22), first_statement_index: 0 }))), [(*_3): i32]);
 //         _4 = &ReErased (*_3);
-//         Validate(Acquire, [(*_4): i32/ReScope(Remainder(BlockRemainder { block: NodeId(41), first_statement_index: 0 })) (imm)]);
+//         Validate(Acquire, [(*_4): i32/ReScope(Remainder(BlockRemainder { block: ItemLocalId(22), first_statement_index: 0 })) (imm)]);
 //         StorageLive(_5);
 //         _5 = (*_4);
 //         _0 = _5;
 //         StorageDead(_5);
 //         StorageDead(_4);
-//         EndRegion(ReScope(Remainder(BlockRemainder { block: NodeId(41), first_statement_index: 0 })));
+//         EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(22), first_statement_index: 0 })));
 //         StorageDead(_3);
 //         return;
 //     }
diff --git a/src/test/mir-opt/validate_3.rs b/src/test/mir-opt/validate_3.rs
index 9140cf5768f59..cd556564b7913 100644
--- a/src/test/mir-opt/validate_3.rs
+++ b/src/test/mir-opt/validate_3.rs
@@ -32,18 +32,18 @@ fn main() {
 // fn main() -> () {
 //     let mut _5: &ReErased i32;
 //     bb0: {
-//         Validate(Suspend(ReScope(Misc(NodeId(46)))), [((*_2).0: i32): i32/ReScope(Remainder(BlockRemainder { block: NodeId(18), first_statement_index: 3 })) (imm)]);
+//         Validate(Suspend(ReScope(Misc(ItemLocalId(17)))), [((*_2).0: i32): i32/ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 })) (imm)]);
 //         _5 = &ReErased ((*_2).0: i32);
-//         Validate(Acquire, [(*_5): i32/ReScope(Misc(NodeId(46))) (imm)]);
-//         Validate(Suspend(ReScope(Misc(NodeId(46)))), [(*_5): i32/ReScope(Misc(NodeId(46))) (imm)]);
+//         Validate(Acquire, [(*_5): i32/ReScope(Misc(ItemLocalId(17))) (imm)]);
+//         Validate(Suspend(ReScope(Misc(ItemLocalId(17)))), [(*_5): i32/ReScope(Misc(ItemLocalId(17))) (imm)]);
 //         _4 = &ReErased (*_5);
-//         Validate(Acquire, [(*_4): i32/ReScope(Misc(NodeId(46))) (imm)]);
-//         Validate(Release, [_3: (), _4: &ReScope(Misc(NodeId(46))) i32]);
+//         Validate(Acquire, [(*_4): i32/ReScope(Misc(ItemLocalId(17))) (imm)]);
+//         Validate(Release, [_3: (), _4: &ReScope(Misc(ItemLocalId(17))) i32]);
 //         _3 = const foo(_4) -> bb1;
 //     }
 //     bb1: {
-//         EndRegion(ReScope(Misc(NodeId(46))));
-//         EndRegion(ReScope(Remainder(BlockRemainder { block: NodeId(18), first_statement_index: 3 })));
+//         EndRegion(ReScope(Misc(ItemLocalId(17))));
+//         EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 })));
 //         return;
 //     }
 // }
diff --git a/src/test/mir-opt/validate_5.rs b/src/test/mir-opt/validate_5.rs
index 0182e6e296445..224f4ce2effe3 100644
--- a/src/test/mir-opt/validate_5.rs
+++ b/src/test/mir-opt/validate_5.rs
@@ -50,12 +50,12 @@ fn main() {
 //         _3 = _2;
 //         StorageLive(_4);
 //         StorageLive(_5);
-//         Validate(Suspend(ReScope(Misc(NodeId(44)))), [(*_3): i32]);
+//         Validate(Suspend(ReScope(Misc(ItemLocalId(9)))), [(*_3): i32]);
 //         _5 = &ReErased mut (*_3);
-//         Validate(Acquire, [(*_5): i32/ReScope(Misc(NodeId(44)))]);
+//         Validate(Acquire, [(*_5): i32/ReScope(Misc(ItemLocalId(9)))]);
 //         _4 = _5 as *mut i32 (Misc);
 //         StorageDead(_5);
-//         EndRegion(ReScope(Misc(NodeId(44))));
+//         EndRegion(ReScope(Misc(ItemLocalId(9))));
 //         Validate(Release, [_0: bool, _4: *mut i32]);
 //         _0 = const write_42(_4) -> bb1;
 //     }