about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/cfg/construct.rs89
-rw-r--r--src/librustc/cfg/graphviz.rs63
-rw-r--r--src/librustc/cfg/mod.rs13
-rw-r--r--src/librustc/hir/map/mod.rs15
-rw-r--r--src/librustc/middle/dataflow.rs96
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs60
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs15
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs12
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs17
-rw-r--r--src/librustc_borrowck/borrowck/move_data.rs55
-rw-r--r--src/librustc_borrowck/graphviz.rs2
-rw-r--r--src/librustc_driver/pretty.rs2
-rw-r--r--src/librustc_lint/builtin.rs26
13 files changed, 249 insertions, 216 deletions
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index e7e2c84fc4e..1448fb7c528 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 944b77dbf01..fa034744b62 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 1473dbb1676..b379d3956e9 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 31b0b5c820e..e54df2d50d8 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> {
@@ -340,6 +343,11 @@ impl<'hir> Map<'hir> {
     }
 
     #[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 d394c0f0c87..e88678dea1d 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 4058f3198af..e83c79fb4a4 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 78787627889..465457f5ab3 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 68bffb90f4d..e14edc43904 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 eca713a98df..0b62da306db 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 217bd6e6ca1..79a4a4f9f4d 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 e3a2bfa3927..22867ba5b55 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 20f2a146b0b..6a58b7fb753 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 3bfe2897de1..0fe30dcabb0 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();