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 + pub exiting_scopes: Vec } 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>, + + /// The reverse mapping of `node_to_hir_id`. + hir_to_node_id: FxHashMap, } 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 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>, + local_id_to_index: FxHashMap>, // 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>) -> &'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>) + -> &'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> { - let mut index = NodeMap(); +fn build_local_id_to_index(body: Option<&hir::Body>, + cfg: &cfg::CFG) + -> FxHashMap> { + 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>, + fn add_entries_from_fn_body(index: &mut FxHashMap>, body: &hir::Body, entry: CFGIndex) { use hir::intravisit::Visitor; struct Formals<'a> { entry: CFGIndex, - index: &'a mut NodeMap>, + index: &'a mut FxHashMap>, } 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(&self, id: ast::NodeId, mut f: F) -> bool where + pub fn each_bit_on_entry(&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(&self, id: ast::NodeId, mut f: F) -> bool where + pub fn each_gen_bit(&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(&self, node: ast::NodeId, mut op: F) -> bool where + pub fn each_issued_loan(&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 { + pub fn loans_generated_by(&self, node: hir::ItemLocalId) -> Vec { //! 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>) { - 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>) @@ -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> @@ -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>, - 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>>, @@ -54,7 +54,7 @@ pub struct MoveData<'tcx> { pub path_assignments: RefCell>, /// Assignments to a variable or path, like `x = foo`, but not `x += foo`. - pub assignee_ids: RefCell, + pub assignee_ids: RefCell>, } 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>, - 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>, - 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>, - 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>, - 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>) -> Option { //! 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(&self, - id: ast::NodeId, + id: hir::ItemLocalId, loan_path: &Rc>, 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(&self, - id: ast::NodeId, + id: hir::ItemLocalId, loan_path: &Rc>, 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, 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();