rustc: use hir::ItemLocalId instead of ast::NodeId in CFG.

This commit is contained in:
Eduard-Mihai Burtescu 2017-08-29 19:27:30 +03:00
parent 45d31e7310
commit 28ddd7a4ef
13 changed files with 249 additions and 216 deletions

View file

@ -12,7 +12,6 @@ use rustc_data_structures::graph;
use cfg::*; use cfg::*;
use middle::region::CodeExtent; use middle::region::CodeExtent;
use ty::{self, TyCtxt}; use ty::{self, TyCtxt};
use syntax::ast;
use syntax::ptr::P; use syntax::ptr::P;
use hir::{self, PatKind}; use hir::{self, PatKind};
@ -30,13 +29,13 @@ struct CFGBuilder<'a, 'tcx: 'a> {
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
struct BlockScope { 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` break_index: CFGIndex, // where to go on `break`
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
struct LoopScope { 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` continue_index: CFGIndex, // where to go on a `loop`
break_index: CFGIndex, // where to go on a `break` 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); cfg_builder.add_contained_edge(body_exit, fn_exit);
let CFGBuilder { graph, .. } = cfg_builder; let CFGBuilder { graph, .. } = cfg_builder;
CFG { CFG {
owner_def_id,
graph, graph,
entry, entry,
exit: fn_exit, exit: fn_exit,
@ -79,10 +79,10 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
fn block(&mut self, blk: &hir::Block, pred: CFGIndex) -> CFGIndex { fn block(&mut self, blk: &hir::Block, pred: CFGIndex) -> CFGIndex {
if blk.targeted_by_break { 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 { self.breakable_block_scopes.push(BlockScope {
block_expr_id: blk.id, block_expr_id: blk.hir_id.local_id,
break_index: expr_exit, break_index: expr_exit,
}); });
@ -104,21 +104,22 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
let expr_exit = self.opt_expr(&blk.expr, stmts_exit); 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 { 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 { match stmt.node {
hir::StmtDecl(ref decl, id) => { hir::StmtDecl(ref decl, _) => {
let exit = self.decl(&decl, pred); 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::StmtExpr(ref expr, _) |
hir::StmtSemi(ref expr, id) => { hir::StmtSemi(ref expr, _) => {
let exit = self.expr(&expr, pred); 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::Path(_) |
PatKind::Lit(..) | PatKind::Lit(..) |
PatKind::Range(..) | 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::Box(ref subpat) |
PatKind::Ref(ref subpat, _) | PatKind::Ref(ref subpat, _) |
PatKind::Binding(.., Some(ref subpat)) => { PatKind::Binding(.., Some(ref subpat)) => {
let subpat_exit = self.pat(&subpat, pred); 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::TupleStruct(_, ref subpats, _) |
PatKind::Tuple(ref subpats, _) => { PatKind::Tuple(ref subpats, _) => {
let pats_exit = self.pats_all(subpats.iter(), pred); 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, _) => { PatKind::Struct(_, ref subpats, _) => {
let pats_exit = self.pats_all(subpats.iter().map(|f| &f.node.pat), pred); 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) => { PatKind::Slice(ref pre, ref vec, ref post) => {
let pre_exit = self.pats_all(pre.iter(), pred); let pre_exit = self.pats_all(pre.iter(), pred);
let vec_exit = self.pats_all(vec.iter(), pre_exit); let vec_exit = self.pats_all(vec.iter(), pre_exit);
let post_exit = self.pats_all(post.iter(), vec_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 { match expr.node {
hir::ExprBlock(ref blk) => { hir::ExprBlock(ref blk) => {
let blk_exit = self.block(&blk, pred); 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) => { 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 cond_exit = self.expr(&cond, pred); // 1
let then_exit = self.expr(&then, cond_exit); // 2 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)) => { 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 cond_exit = self.expr(&cond, pred); // 1
let then_exit = self.expr(&then, cond_exit); // 2 let then_exit = self.expr(&then, cond_exit); // 2
let else_exit = self.expr(&otherwise, cond_exit); // 3 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, _) => { hir::ExprWhile(ref cond, ref body, _) => {
@ -245,12 +246,12 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
let loopback = self.add_dummy_node(&[pred]); // 1 let loopback = self.add_dummy_node(&[pred]); // 1
// Create expr_exit without pred (cond_exit) // 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 // 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) // condition and the body of the loop (both can break out of the loop)
self.loop_scopes.push(LoopScope { self.loop_scopes.push(LoopScope {
loop_id: expr.id, loop_id: expr.hir_id.local_id,
continue_index: loopback, continue_index: loopback,
break_index: expr_exit break_index: expr_exit
}); });
@ -282,9 +283,9 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
// may cause additional edges. // may cause additional edges.
let loopback = self.add_dummy_node(&[pred]); // 1 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 { self.loop_scopes.push(LoopScope {
loop_id: expr.id, loop_id: expr.hir_id.local_id,
continue_index: loopback, continue_index: loopback,
break_index: expr_exit, break_index: expr_exit,
}); });
@ -295,7 +296,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
} }
hir::ExprMatch(ref discr, ref arms, _) => { 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() => { 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 l_exit = self.expr(&l, pred); // 1
let r_exit = self.expr(&r, l_exit); // 2 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) => { hir::ExprRet(ref v) => {
let v_exit = self.opt_expr(v, pred); 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_returning_edge(expr, b);
self.add_unreachable_node() self.add_unreachable_node()
} }
hir::ExprBreak(destination, ref opt_expr) => { hir::ExprBreak(destination, ref opt_expr) => {
let v = self.opt_expr(opt_expr, pred); 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); self.find_scope_edge(expr, destination, ScopeCfKind::Break);
let b = self.add_ast_node(expr.id, &[v]); let b = self.add_ast_node(expr.hir_id.local_id, &[v]);
self.add_exiting_edge(expr, b, scope_id, break_dest); self.add_exiting_edge(expr, b, target_scope, break_dest);
self.add_unreachable_node() self.add_unreachable_node()
} }
hir::ExprAgain(destination) => { hir::ExprAgain(destination) => {
let (scope_id, cont_dest) = let (target_scope, cont_dest) =
self.find_scope_edge(expr, destination, ScopeCfKind::Continue); self.find_scope_edge(expr, destination, ScopeCfKind::Continue);
let a = self.add_ast_node(expr.id, &[pred]); let a = self.add_ast_node(expr.hir_id.local_id, &[pred]);
self.add_exiting_edge(expr, a, scope_id, cont_dest); self.add_exiting_edge(expr, a, target_scope, cont_dest);
self.add_unreachable_node() self.add_unreachable_node()
} }
@ -397,7 +398,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
hir::ExprInlineAsm(_, ref outputs, ref inputs) => { hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
let post_outputs = self.exprs(outputs.iter().map(|e| &*e), pred); let post_outputs = self.exprs(outputs.iter().map(|e| &*e), pred);
let post_inputs = self.exprs(inputs.iter().map(|e| &*e), post_outputs); 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(..) | hir::ExprClosure(..) |
@ -444,10 +445,10 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
//! Handles case of an expression that evaluates `subexprs` in order //! Handles case of an expression that evaluates `subexprs` in order
let subexprs_exit = self.exprs(subexprs, pred); 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 { arms: &[hir::Arm], pred: CFGIndex) -> CFGIndex {
// The CFG for match expression is quite complex, so no ASCII // The CFG for match expression is quite complex, so no ASCII
// art for it (yet). // art for it (yet).
@ -552,8 +553,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
self.add_node(CFGNodeData::Dummy, preds) self.add_node(CFGNodeData::Dummy, preds)
} }
fn add_ast_node(&mut self, id: ast::NodeId, preds: &[CFGIndex]) -> CFGIndex { fn add_ast_node(&mut self, id: hir::ItemLocalId, preds: &[CFGIndex]) -> CFGIndex {
assert!(id != ast::DUMMY_NODE_ID);
self.add_node(CFGNodeData::AST(id), preds) self.add_node(CFGNodeData::AST(id), preds)
} }
@ -579,14 +579,13 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
fn add_exiting_edge(&mut self, fn add_exiting_edge(&mut self,
from_expr: &hir::Expr, from_expr: &hir::Expr,
from_index: CFGIndex, from_index: CFGIndex,
scope_id: ast::NodeId, target_scope: CodeExtent,
to_index: CFGIndex) { to_index: CFGIndex) {
let mut data = CFGEdgeData { exiting_scopes: vec![] }; let mut data = CFGEdgeData { exiting_scopes: vec![] };
let mut scope = CodeExtent::Misc(from_expr.id); 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); let region_maps = self.tcx.region_maps(self.owner_def_id);
while scope != target_scope { 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); scope = region_maps.encl_scope(scope);
} }
self.graph.add_edge(from_index, to_index, data); self.graph.add_edge(from_index, to_index, data);
@ -607,13 +606,13 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
fn find_scope_edge(&self, fn find_scope_edge(&self,
expr: &hir::Expr, expr: &hir::Expr,
destination: hir::Destination, destination: hir::Destination,
scope_cf_kind: ScopeCfKind) -> (ast::NodeId, CFGIndex) { scope_cf_kind: ScopeCfKind) -> (CodeExtent, CFGIndex) {
match destination.target_id { match destination.target_id {
hir::ScopeTarget::Block(block_expr_id) => { hir::ScopeTarget::Block(block_expr_id) => {
for b in &self.breakable_block_scopes { for b in &self.breakable_block_scopes {
if b.block_expr_id == block_expr_id { if b.block_expr_id == self.tcx.hir.node_to_hir_id(block_expr_id).local_id {
return (block_expr_id, match scope_cf_kind { return (CodeExtent::Misc(block_expr_id), match scope_cf_kind {
ScopeCfKind::Break => b.break_index, ScopeCfKind::Break => b.break_index,
ScopeCfKind::Continue => bug!("can't continue to block"), 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)) => { hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(loop_id)) => {
for l in &self.loop_scopes { for l in &self.loop_scopes {
if l.loop_id == loop_id { if l.loop_id == self.tcx.hir.node_to_hir_id(loop_id).local_id {
return (loop_id, match scope_cf_kind { return (CodeExtent::Misc(loop_id), match scope_cf_kind {
ScopeCfKind::Break => l.break_index, ScopeCfKind::Break => l.break_index,
ScopeCfKind::Continue => l.continue_index, ScopeCfKind::Continue => l.continue_index,
}); });

View file

@ -15,40 +15,47 @@
use graphviz as dot; use graphviz as dot;
use graphviz::IntoCow; use graphviz::IntoCow;
use syntax::ast;
use hir::map as hir_map;
use cfg; use cfg;
use hir;
use ty::TyCtxt;
pub type Node<'a> = (cfg::CFGIndex, &'a cfg::CFGNode); pub type Node<'a> = (cfg::CFGIndex, &'a cfg::CFGNode);
pub type Edge<'a> = &'a cfg::CFGEdge; pub type Edge<'a> = &'a cfg::CFGEdge;
pub struct LabelledCFG<'a, 'hir: 'a> { pub struct LabelledCFG<'a, 'tcx: 'a> {
pub hir_map: &'a hir_map::Map<'hir>, pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub cfg: &'a cfg::CFG, pub cfg: &'a cfg::CFG,
pub name: String, pub name: String,
/// `labelled_edges` controls whether we emit labels on the edges /// `labelled_edges` controls whether we emit labels on the edges
pub labelled_edges: bool, pub labelled_edges: bool,
} }
fn replace_newline_with_backslash_l(s: String) -> String { impl<'a, 'tcx> LabelledCFG<'a, 'tcx> {
// Replacing newlines with \\l causes each line to be left-aligned, fn local_id_to_string(&self, local_id: hir::ItemLocalId) -> String {
// improving presentation of (long) pretty-printed expressions. let node_id = self.tcx.hir.hir_to_node_id(hir::HirId {
if s.contains("\n") { owner: self.tcx.closure_base_def_id(self.cfg.owner_def_id).index,
let mut s = s.replace("\n", "\\l"); local_id
// Apparently left-alignment applies to the line that precedes });
// \l, not the line that follows; so, add \l at end of string let s = self.tcx.hir.node_to_string(node_id);
// if not already present, ensuring last line gets left-aligned
// as well. // Replacing newlines with \\l causes each line to be left-aligned,
let mut last_two: Vec<_> = // improving presentation of (long) pretty-printed expressions.
s.chars().rev().take(2).collect(); if s.contains("\n") {
last_two.reverse(); let mut s = s.replace("\n", "\\l");
if last_two != ['\\', 'l'] { // Apparently left-alignment applies to the line that precedes
s.push_str("\\l"); // \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()) dot::LabelText::LabelStr("entry".into_cow())
} else if i == self.cfg.exit { } else if i == self.cfg.exit {
dot::LabelText::LabelStr("exit".into_cow()) 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()) dot::LabelText::LabelStr("(dummy_node)".into_cow())
} else { } else {
let s = self.hir_map.node_to_string(n.data.id()); let s = self.local_id_to_string(n.data.id());
// left-aligns the lines
let s = replace_newline_with_backslash_l(s);
dot::LabelText::EscStr(s.into_cow()) 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()); return dot::LabelText::EscStr(label.into_cow());
} }
let mut put_one = false; 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 { if put_one {
label.push_str(",\\l"); label.push_str(",\\l");
} else { } else {
put_one = true; put_one = true;
} }
let s = self.hir_map.node_to_string(node_id); let s = self.local_id_to_string(id);
// left-aligns the lines
let s = replace_newline_with_backslash_l(s);
label.push_str(&format!("exiting scope_{} {}", label.push_str(&format!("exiting scope_{} {}",
i, i,
&s[..])); &s[..]));

View file

@ -13,13 +13,14 @@
use rustc_data_structures::graph; use rustc_data_structures::graph;
use ty::TyCtxt; use ty::TyCtxt;
use syntax::ast;
use hir; use hir;
use hir::def_id::DefId;
mod construct; mod construct;
pub mod graphviz; pub mod graphviz;
pub struct CFG { pub struct CFG {
pub owner_def_id: DefId,
pub graph: CFGGraph, pub graph: CFGGraph,
pub entry: CFGIndex, pub entry: CFGIndex,
pub exit: CFGIndex, pub exit: CFGIndex,
@ -27,7 +28,7 @@ pub struct CFG {
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
pub enum CFGNodeData { pub enum CFGNodeData {
AST(ast::NodeId), AST(hir::ItemLocalId),
Entry, Entry,
Exit, Exit,
Dummy, Dummy,
@ -35,18 +36,18 @@ pub enum CFGNodeData {
} }
impl CFGNodeData { impl CFGNodeData {
pub fn id(&self) -> ast::NodeId { pub fn id(&self) -> hir::ItemLocalId {
if let CFGNodeData::AST(id) = *self { if let CFGNodeData::AST(id) = *self {
id id
} else { } else {
ast::DUMMY_NODE_ID hir::DUMMY_ITEM_LOCAL_ID
} }
} }
} }
#[derive(Debug)] #[derive(Debug)]
pub struct CFGEdgeData { pub struct CFGEdgeData {
pub exiting_scopes: Vec<ast::NodeId> pub exiting_scopes: Vec<hir::ItemLocalId>
} }
pub type CFGIndex = graph::NodeIndex; pub type CFGIndex = graph::NodeIndex;
@ -63,7 +64,7 @@ impl CFG {
construct::construct(tcx, body) 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) self.graph.depth_traverse(self.entry, graph::OUTGOING)
.any(|idx| self.graph.node_data(idx).id() == id) .any(|idx| self.graph.node_data(idx).id() == id)
} }

View file

@ -26,7 +26,7 @@ use syntax_pos::Span;
use hir::*; use hir::*;
use hir::print::Nested; use hir::print::Nested;
use util::nodemap::DefIdMap; use util::nodemap::{DefIdMap, FxHashMap};
use arena::TypedArena; use arena::TypedArena;
use std::cell::RefCell; use std::cell::RefCell;
@ -251,6 +251,9 @@ pub struct Map<'hir> {
/// Bodies inlined from other crates are cached here. /// Bodies inlined from other crates are cached here.
inlined_bodies: RefCell<DefIdMap<&'hir Body>>, 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> { impl<'hir> Map<'hir> {
@ -339,6 +342,11 @@ impl<'hir> Map<'hir> {
self.definitions.as_local_node_id(def_id) 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] #[inline]
pub fn node_to_hir_id(&self, node_id: NodeId) -> HirId { pub fn node_to_hir_id(&self, node_id: NodeId) -> HirId {
self.definitions.node_to_hir_id(node_id) 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.); 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 { let map = Map {
forest, forest,
dep_graph: forest.dep_graph.clone(), dep_graph: forest.dep_graph.clone(),
map, map,
hir_to_node_id,
definitions, definitions,
inlined_bodies: RefCell::new(DefIdMap()), inlined_bodies: RefCell::new(DefIdMap()),
}; };

View file

@ -20,12 +20,11 @@ use ty::TyCtxt;
use std::io; use std::io;
use std::mem; use std::mem;
use std::usize; use std::usize;
use syntax::ast;
use syntax::print::pprust::PrintState; use syntax::print::pprust::PrintState;
use rustc_data_structures::graph::OUTGOING; use rustc_data_structures::graph::OUTGOING;
use util::nodemap::NodeMap; use util::nodemap::FxHashMap;
use hir; use hir;
use hir::intravisit::{self, IdRange}; use hir::intravisit::{self, IdRange};
use hir::print as pprust; use hir::print as pprust;
@ -56,7 +55,7 @@ pub struct DataFlowContext<'a, 'tcx: 'a, O> {
// mapping from node to cfg node index // mapping from node to cfg node index
// FIXME (#6298): Shouldn't this go with CFG? // 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`, // Bit sets per cfg node. The following three fields (`gens`, `kills`,
// and `on_entry`) all have the same structure. For each id in // 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 changed: bool
} }
fn get_cfg_indices<'a>(id: ast::NodeId, index: &'a NodeMap<Vec<CFGIndex>>) -> &'a [CFGIndex] { fn get_cfg_indices<'a>(id: hir::ItemLocalId,
let opt_indices = index.get(&id); index: &'a FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>)
opt_indices.map(|v| &v[..]).unwrap_or(&[]) -> &'a [CFGIndex] {
index.get(&id).map_or(&[], |v| &v[..])
} }
impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
fn has_bitset_for_nodeid(&self, n: ast::NodeId) -> bool { fn has_bitset_for_local_id(&self, n: hir::ItemLocalId) -> bool {
assert!(n != ast::DUMMY_NODE_ID); assert!(n != hir::DUMMY_ITEM_LOCAL_ID);
self.nodeid_to_index.contains_key(&n) 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, ps: &mut pprust::State,
node: pprust::AnnNode) -> io::Result<()> { node: pprust::AnnNode) -> io::Result<()> {
let id = match node { let id = match node {
pprust::NodeName(_) => ast::CRATE_NODE_ID, pprust::NodeName(_) => return Ok(()),
pprust::NodeExpr(expr) => expr.id, pprust::NodeExpr(expr) => expr.hir_id.local_id,
pprust::NodeBlock(blk) => blk.id, pprust::NodeBlock(blk) => blk.hir_id.local_id,
pprust::NodeItem(_) | pprust::NodeSubItem(_) => ast::CRATE_NODE_ID, pprust::NodeItem(_) |
pprust::NodePat(pat) => pat.id 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(()); return Ok(());
} }
assert!(self.bits_per_id > 0); 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 { for &cfgidx in indices {
let (start, end) = self.compute_id_range(cfgidx); let (start, end) = self.compute_id_range(cfgidx);
let on_entry = &self.on_entry[start.. end]; 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( ps.synth_comment(
format!("id {}: {}{}{}{}", id, entry_str, format!("id {}: {}{}{}{}", id.as_usize(), entry_str,
gens_str, action_kills_str, scope_kills_str))?; gens_str, action_kills_str, scope_kills_str))?;
ps.s.space()?; 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>, fn build_local_id_to_index(body: Option<&hir::Body>,
cfg: &cfg::CFG) -> NodeMap<Vec<CFGIndex>> { cfg: &cfg::CFG)
let mut index = NodeMap(); -> FxHashMap<hir::ItemLocalId, Vec<CFGIndex>> {
let mut index = FxHashMap();
// FIXME (#6298): Would it be better to fold formals from decl // FIXME (#6298): Would it be better to fold formals from decl
// into cfg itself? i.e. introduce a fn-based flow-graph in // 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 /// Add mappings from the ast nodes for the formal bindings to
/// the entry-node in the graph. /// 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, body: &hir::Body,
entry: CFGIndex) { entry: CFGIndex) {
use hir::intravisit::Visitor; use hir::intravisit::Visitor;
struct Formals<'a> { struct Formals<'a> {
entry: CFGIndex, entry: CFGIndex,
index: &'a mut NodeMap<Vec<CFGIndex>>, index: &'a mut FxHashMap<hir::ItemLocalId, Vec<CFGIndex>>,
} }
let mut formals = Formals { entry: entry, index: index }; let mut formals = Formals { entry: entry, index: index };
for arg in &body.arguments { 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) { 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) intravisit::walk_pat(self, p)
} }
} }
@ -259,13 +261,13 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
let kills2 = zeroes; let kills2 = zeroes;
let on_entry = vec![entry; num_nodes * words_per_id]; 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 { DataFlowContext {
tcx, tcx,
analysis_name, analysis_name,
words_per_id, words_per_id,
nodeid_to_index, local_id_to_index,
bits_per_id, bits_per_id,
oper, oper,
gens, 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` //! Indicates that `id` generates `bit`
debug!("{} add_gen(id={}, bit={})", debug!("{} add_gen(id={:?}, bit={})",
self.analysis_name, 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); 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 { for &cfgidx in indices {
let (start, end) = self.compute_id_range(cfgidx); let (start, end) = self.compute_id_range(cfgidx);
let gens = &mut self.gens[start.. end]; 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` //! Indicates that `id` kills `bit`
debug!("{} add_kill(id={}, bit={})", debug!("{} add_kill(id={:?}, bit={})",
self.analysis_name, 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); 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 { for &cfgidx in indices {
let (start, end) = self.compute_id_range(cfgidx); let (start, end) = self.compute_id_range(cfgidx);
let kills = match kind { 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, F: FnMut(usize) -> bool,
{ {
//! Iterates through each bit that is set on entry to `id`. //! Iterates through each bit that is set on entry to `id`.
//! Only useful after `propagate()` has been called. //! Only useful after `propagate()` has been called.
if !self.has_bitset_for_nodeid(id) { if !self.has_bitset_for_local_id(id) {
return true; 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 { for &cfgidx in indices {
if !self.each_bit_for_node(EntryOrExit::Entry, cfgidx, |i| f(i)) { if !self.each_bit_for_node(EntryOrExit::Entry, cfgidx, |i| f(i)) {
return false; return false;
@ -387,11 +389,11 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
self.each_bit(slice, f) 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, F: FnMut(usize) -> bool,
{ {
//! Iterates through each bit in the gen set for `id`. //! 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; return true;
} }
@ -401,11 +403,11 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
return true; 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 { for &cfgidx in indices {
let (start, end) = self.compute_id_range(cfgidx); let (start, end) = self.compute_id_range(cfgidx);
let gens = &self.gens[start.. end]; 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)); self.analysis_name, id, bits_to_string(gens));
if !self.each_bit(gens, |i| f(i)) { if !self.each_bit(gens, |i| f(i)) {
return false; 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 orig_kills = self.scope_kills[start.. end].to_vec();
let mut changed = false; let mut changed = false;
for &node_id in &edge.data.exiting_scopes { for &id in &edge.data.exiting_scopes {
let opt_cfg_idx = self.nodeid_to_index.get(&node_id); let opt_cfg_idx = self.local_id_to_index.get(&id);
match opt_cfg_idx { match opt_cfg_idx {
Some(indices) => { Some(indices) => {
for &cfg_idx in indices { for &cfg_idx in indices {
let (start, end) = self.compute_id_range(cfg_idx); let (start, end) = self.compute_id_range(cfg_idx);
let kills = &self.scope_kills[start.. end]; let kills = &self.scope_kills[start.. end];
if bitwise(&mut orig_kills, kills, &Union) { if bitwise(&mut orig_kills, kills, &Union) {
debug!("scope exits: scope id={} \ debug!("scope exits: scope id={:?} \
(node={:?} of {:?}) added killset: {}", (node={:?} of {:?}) added killset: {}",
node_id, cfg_idx, indices, id, cfg_idx, indices,
bits_to_string(kills)); bits_to_string(kills));
changed = true; changed = true;
} }
@ -490,8 +492,8 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
} }
None => { None => {
debug!("{} add_kills_from_flow_exits flow_exit={:?} \ debug!("{} add_kills_from_flow_exits flow_exit={:?} \
no cfg_idx for exiting_scope={}", no cfg_idx for exiting_scope={:?}",
self.analysis_name, flow_exit, node_id); 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 // Iterate over nodes in reverse postorder
for &node_index in nodes_po.iter().rev() { for &node_index in nodes_po.iter().rev() {
let node = cfg.graph.node(node_index); 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)); node_index, node.data.id(), bits_to_string(in_out));
let (start, end) = self.dfcx.compute_id_range(node_index); let (start, end) = self.dfcx.compute_id_range(node_index);

View file

@ -103,7 +103,8 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
debug!("consume(consume_id={}, cmt={:?}, mode={:?})", debug!("consume(consume_id={}, cmt={:?}, mode={:?})",
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, fn matched_pat(&mut self,
@ -120,7 +121,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
cmt, cmt,
mode); 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, fn borrow(&mut self,
@ -136,15 +137,16 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
borrow_id, cmt, loan_region, borrow_id, cmt, loan_region,
bk, loan_cause); bk, loan_cause);
let hir_id = self.tcx().hir.node_to_hir_id(borrow_id);
if let Some(lp) = opt_loan_path(&cmt) { if let Some(lp) = opt_loan_path(&cmt) {
let moved_value_use_kind = match loan_cause { let moved_value_use_kind = match loan_cause {
euv::ClosureCapture(_) => MovedInCapture, euv::ClosureCapture(_) => MovedInCapture,
_ => MovedInUse, _ => 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, 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 // have to be *FULLY* initialized, but we still
// must be careful lest it contains derefs of // must be careful lest it contains derefs of
// pointers. // 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, assignment_span,
MovedInUse, MovedInUse,
&lp); &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 // In a case like `path += 1`, then path must be
// fully initialized, since we will read it before // fully initialized, since we will read it before
// we write it. // 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, assignment_span,
MovedInUse, MovedInUse,
&lp); &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) { } 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> { impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.bccx.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, F: FnMut(&Loan<'tcx>) -> bool,
{ {
//! Iterates over each loan that has been issued //! 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 //! Like `each_issued_loan()`, but only considers loans that are
//! currently in scope. //! 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) { if self.bccx.region_maps.is_subscope_of(scope, loan.kill_scope) {
op(loan) op(loan)
} else { } else {
@ -325,7 +330,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
return true; 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 //! Returns a vector of the loans that are generated as
//! we enter `node`. //! we enter `node`.
@ -337,7 +342,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
return result; 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 //! Checks to see whether any of the loans that are issued
//! on entrance to `node` conflict with loans that have already been //! on entrance to `node` conflict with loans that have already been
//! issued when we enter `node` (for example, we do not //! issued when we enter `node` (for example, we do not
@ -590,7 +595,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
} }
fn consume_common(&self, fn consume_common(&self,
id: ast::NodeId, id: hir::ItemLocalId,
span: Span, span: Span,
cmt: mc::cmt<'tcx>, cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode) { mode: euv::ConsumeMode) {
@ -628,7 +633,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
} }
fn check_for_copy_of_frozen_path(&self, fn check_for_copy_of_frozen_path(&self,
id: ast::NodeId, id: hir::ItemLocalId,
span: Span, span: Span,
copy_path: &LoanPath<'tcx>) { copy_path: &LoanPath<'tcx>) {
match self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow) { 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, fn check_for_move_of_borrowed_path(&self,
id: ast::NodeId, id: hir::ItemLocalId,
span: Span, span: Span,
move_path: &LoanPath<'tcx>, move_path: &LoanPath<'tcx>,
move_kind: move_data::MoveKind) { move_kind: move_data::MoveKind) {
@ -699,18 +704,21 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
} }
pub fn analyze_restrictions_on_use(&self, pub fn analyze_restrictions_on_use(&self,
expr_id: ast::NodeId, expr_id: hir::ItemLocalId,
use_path: &LoanPath<'tcx>, use_path: &LoanPath<'tcx>,
borrow_kind: ty::BorrowKind) borrow_kind: ty::BorrowKind)
-> UseError<'tcx> { -> UseError<'tcx> {
debug!("analyze_restrictions_on_use(expr_id={}, use_path={:?})", debug!("analyze_restrictions_on_use(expr_id={:?}, use_path={:?})",
self.tcx().hir.node_to_string(expr_id), expr_id, use_path);
use_path);
let mut ret = UseOk; 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( 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) { if !compatible_borrow_kinds(loan.kind, borrow_kind) {
ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span); ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span);
false false
@ -725,11 +733,11 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
/// Reports an error if `expr` (which should be a path) /// Reports an error if `expr` (which should be a path)
/// is using a moved/uninitialized value /// is using a moved/uninitialized value
fn check_if_path_is_moved(&self, fn check_if_path_is_moved(&self,
id: ast::NodeId, id: hir::ItemLocalId,
span: Span, span: Span,
use_kind: MovedValueUseKind, use_kind: MovedValueUseKind,
lp: &Rc<LoanPath<'tcx>>) { 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); id, use_kind, lp);
// FIXME (22079): if you find yourself tempted to cut and paste // 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 /// (*p).x = 22; // not ok, p is uninitialized, can't deref
/// ``` /// ```
fn check_if_assigned_path_is_moved(&self, fn check_if_assigned_path_is_moved(&self,
id: ast::NodeId, id: hir::ItemLocalId,
span: Span, span: Span,
use_kind: MovedValueUseKind, use_kind: MovedValueUseKind,
lp: &Rc<LoanPath<'tcx>>) lp: &Rc<LoanPath<'tcx>>)
@ -822,14 +830,18 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
} }
fn check_assignment(&self, fn check_assignment(&self,
assignment_id: ast::NodeId, assignment_id: hir::ItemLocalId,
assignment_span: Span, assignment_span: Span,
assignee_cmt: mc::cmt<'tcx>) { assignee_cmt: mc::cmt<'tcx>) {
debug!("check_assignment(assignee_cmt={:?})", assignee_cmt); debug!("check_assignment(assignee_cmt={:?})", assignee_cmt);
// Check that we don't invalidate any outstanding loans // Check that we don't invalidate any outstanding loans
if let Some(loan_path) = opt_loan_path(&assignee_cmt) { 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.each_in_scope_loan_affecting_path(scope, &loan_path, |loan| {
self.report_illegal_mutation(assignment_span, &loan_path, loan); self.report_illegal_mutation(assignment_span, &loan_path, loan);
false false

View file

@ -27,7 +27,7 @@ use rustc::hir::*;
use rustc::hir::map::Node::*; use rustc::hir::map::Node::*;
struct GatherMoveInfo<'tcx> { struct GatherMoveInfo<'tcx> {
id: ast::NodeId, id: hir::ItemLocalId,
kind: MoveKind, kind: MoveKind,
cmt: mc::cmt<'tcx>, cmt: mc::cmt<'tcx>,
span_path_opt: Option<MovePlace<'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_id: ast::NodeId,
var_ty: Ty<'tcx>) { var_ty: Ty<'tcx>) {
let loan_path = Rc::new(LoanPath::new(LpVar(var_id), var_ty)); 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>, pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
move_data: &MoveData<'tcx>, move_data: &MoveData<'tcx>,
move_error_collector: &mut MoveErrorCollector<'tcx>, move_error_collector: &mut MoveErrorCollector<'tcx>,
move_expr_id: ast::NodeId, move_expr_id: hir::ItemLocalId,
cmt: mc::cmt<'tcx>, cmt: mc::cmt<'tcx>,
move_reason: euv::MoveReason) { move_reason: euv::MoveReason) {
let kind = match move_reason { let kind = match move_reason {
@ -118,7 +119,7 @@ pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
_ => None, _ => None,
}; };
let move_info = GatherMoveInfo { let move_info = GatherMoveInfo {
id: move_pat.id, id: move_pat.hir_id.local_id,
kind: MovePat, kind: MovePat,
cmt, cmt,
span_path_opt: pat_span_path_opt, 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_data: &MoveData<'tcx>,
move_error_collector: &mut MoveErrorCollector<'tcx>, move_error_collector: &mut MoveErrorCollector<'tcx>,
move_info: GatherMoveInfo<'tcx>) { move_info: GatherMoveInfo<'tcx>) {
debug!("gather_move(move_id={}, cmt={:?})", debug!("gather_move(move_id={:?}, cmt={:?})",
move_info.id, move_info.cmt); move_info.id, move_info.cmt);
let potentially_illegal_move = 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>, pub fn gather_assignment<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
move_data: &MoveData<'tcx>, move_data: &MoveData<'tcx>,
assignment_id: ast::NodeId, assignment_id: hir::ItemLocalId,
assignment_span: Span, assignment_span: Span,
assignee_loan_path: Rc<LoanPath<'tcx>>, assignee_loan_path: Rc<LoanPath<'tcx>>,
assignee_id: ast::NodeId, assignee_id: hir::ItemLocalId,
mode: euv::MutateMode) { mode: euv::MutateMode) {
move_data.add_assignment(bccx.tcx, move_data.add_assignment(bccx.tcx,
assignee_loan_path, assignee_loan_path,

View file

@ -44,7 +44,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
bccx, bccx,
all_loans: Vec::new(), all_loans: Vec::new(),
item_ub: region::CodeExtent::Misc(body.node_id), item_ub: region::CodeExtent::Misc(body.node_id),
move_data: MoveData::new(), move_data: MoveData::default(),
move_error_collector: move_error::MoveErrorCollector::new(), 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) => { euv::Move(move_reason) => {
gather_moves::gather_move_from_expr( gather_moves::gather_move_from_expr(
self.bccx, &self.move_data, &mut self.move_error_collector, 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 => { } euv::Copy => { }
} }
@ -272,8 +272,12 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
self.mark_loan_path_as_mutated(&lp); self.mark_loan_path_as_mutated(&lp);
} }
gather_moves::gather_assignment(self.bccx, &self.move_data, gather_moves::gather_assignment(self.bccx, &self.move_data,
assignment_id, assignment_span, self.bccx.tcx.hir.node_to_hir_id(assignment_id)
lp, cmt.id, mode); .local_id,
assignment_span,
lp,
self.bccx.tcx.hir.node_to_hir_id(cmt.id).local_id,
mode);
} }
None => { None => {
// This can occur with e.g. `*foo() = 5`. In such // This can occur with e.g. `*foo() = 5`. In such

View file

@ -167,9 +167,11 @@ fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>(this: &mut BorrowckCtxt<'a, 'tc
id_range, id_range,
all_loans.len()); all_loans.len());
for (loan_idx, loan) in all_loans.iter().enumerate() { 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_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.add_kills_from_flow_exits(cfg);
loan_dfcx.propagate(cfg, this.body); 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 // Get type of value and span where it was previously
// moved. // 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 { let (move_span, move_note) = match the_move.kind {
move_data::Declared => { move_data::Declared => {
unreachable!(); unreachable!();
} }
move_data::MoveExpr | move_data::MoveExpr |
move_data::MovePat => move_data::MovePat => (self.tcx.hir.span(node_id), ""),
(self.tcx.hir.span(the_move.id), ""),
move_data::Captured => 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, 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), the_move.id, r),
}, " (into closure)"), }, " (into closure)"),
}; };

View file

@ -23,16 +23,16 @@ use rustc::middle::expr_use_visitor as euv;
use rustc::middle::expr_use_visitor::MutateMode; use rustc::middle::expr_use_visitor::MutateMode;
use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization as mc;
use rustc::ty::{self, TyCtxt}; use rustc::ty::{self, TyCtxt};
use rustc::util::nodemap::{FxHashMap, NodeSet}; use rustc::util::nodemap::{FxHashMap, FxHashSet};
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use std::usize; use std::usize;
use syntax::ast;
use syntax_pos::Span; use syntax_pos::Span;
use rustc::hir; use rustc::hir;
use rustc::hir::intravisit::IdRange; use rustc::hir::intravisit::IdRange;
#[derive(Default)]
pub struct MoveData<'tcx> { pub struct MoveData<'tcx> {
/// Move paths. See section "Move paths" in `README.md`. /// Move paths. See section "Move paths" in `README.md`.
pub paths: RefCell<Vec<MovePath<'tcx>>>, pub paths: RefCell<Vec<MovePath<'tcx>>>,
@ -54,7 +54,7 @@ pub struct MoveData<'tcx> {
pub path_assignments: RefCell<Vec<Assignment>>, pub path_assignments: RefCell<Vec<Assignment>>,
/// Assignments to a variable or path, like `x = foo`, but not `x += foo`. /// 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> { pub struct FlowedMoveData<'a, 'tcx: 'a> {
@ -133,7 +133,7 @@ pub struct Move {
pub path: MovePathIndex, pub path: MovePathIndex,
/// id of node that is doing the move. /// id of node that is doing the move.
pub id: ast::NodeId, pub id: hir::ItemLocalId,
/// Kind of move, for error messages. /// Kind of move, for error messages.
pub kind: MoveKind, pub kind: MoveKind,
@ -148,13 +148,13 @@ pub struct Assignment {
pub path: MovePathIndex, pub path: MovePathIndex,
/// id where assignment occurs /// id where assignment occurs
pub id: ast::NodeId, pub id: hir::ItemLocalId,
/// span of node where assignment occurs /// span of node where assignment occurs
pub span: Span, pub span: Span,
/// id for l-value expression on lhs of assignment /// id for l-value expression on lhs of assignment
pub assignee_id: ast::NodeId, pub assignee_id: hir::ItemLocalId,
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -189,17 +189,6 @@ fn loan_path_is_precise(loan_path: &LoanPath) -> bool {
} }
impl<'a, 'tcx> MoveData<'tcx> { 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 /// return true if there are no trackable assignments or moves
/// in this move data - that means that there is nothing that /// in this move data - that means that there is nothing that
/// could cause a borrow error. /// 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`. /// 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>, pub fn add_move(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
orig_lp: Rc<LoanPath<'tcx>>, orig_lp: Rc<LoanPath<'tcx>>,
id: ast::NodeId, id: hir::ItemLocalId,
kind: MoveKind) { kind: MoveKind) {
// Moving one union field automatically moves all its fields. Also move siblings of // Moving one union field automatically moves all its fields. Also move siblings of
// all parent union fields, moves do not propagate upwards automatically. // 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>, fn add_move_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
lp: Rc<LoanPath<'tcx>>, lp: Rc<LoanPath<'tcx>>,
id: ast::NodeId, id: hir::ItemLocalId,
kind: MoveKind) { kind: MoveKind) {
debug!("add_move(lp={:?}, id={}, kind={:?})", debug!("add_move(lp={:?}, id={:?}, kind={:?})",
lp, lp,
id, id,
kind); kind);
@ -398,9 +387,9 @@ impl<'a, 'tcx> MoveData<'tcx> {
/// `span`. /// `span`.
pub fn add_assignment(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn add_assignment(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
lp: Rc<LoanPath<'tcx>>, lp: Rc<LoanPath<'tcx>>,
assign_id: ast::NodeId, assign_id: hir::ItemLocalId,
span: Span, span: Span,
assignee_id: ast::NodeId, assignee_id: hir::ItemLocalId,
mode: euv::MutateMode) { mode: euv::MutateMode) {
// Assigning to one union field automatically assigns to all its fields. // 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 { 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>, fn add_assignment_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
lp: Rc<LoanPath<'tcx>>, lp: Rc<LoanPath<'tcx>>,
assign_id: ast::NodeId, assign_id: hir::ItemLocalId,
span: Span, span: Span,
assignee_id: ast::NodeId, assignee_id: hir::ItemLocalId,
mode: euv::MutateMode) { mode: euv::MutateMode) {
debug!("add_assignment(lp={:?}, assign_id={}, assignee_id={}", debug!("add_assignment(lp={:?}, assign_id={:?}, assignee_id={:?}",
lp, assign_id, assignee_id); lp, assign_id, assignee_id);
let path_index = self.move_path(tcx, lp.clone()); let path_index = self.move_path(tcx, lp.clone());
@ -496,7 +485,8 @@ impl<'a, 'tcx> MoveData<'tcx> {
LpVar(..) | LpUpvar(..) | LpDowncast(..) => { LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
let kill_scope = path.loan_path.kill_scope(bccx); let kill_scope = path.loan_path.kill_scope(bccx);
let path = *self.path_map.borrow().get(&path.loan_path).unwrap(); 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); KillFrom::ScopeEnd, dfcx_moves);
} }
LpExtend(..) => {} LpExtend(..) => {}
@ -511,7 +501,8 @@ impl<'a, 'tcx> MoveData<'tcx> {
LpVar(..) | LpUpvar(..) | LpDowncast(..) => { LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
let kill_scope = lp.kill_scope(bccx); let kill_scope = lp.kill_scope(bccx);
dfcx_assign.add_kill(KillFrom::ScopeEnd, 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); assignment_index);
} }
LpExtend(..) => { LpExtend(..) => {
@ -579,7 +570,7 @@ impl<'a, 'tcx> MoveData<'tcx> {
fn kill_moves(&self, fn kill_moves(&self,
path: MovePathIndex, path: MovePathIndex,
kill_id: ast::NodeId, kill_id: hir::ItemLocalId,
kill_kind: KillFrom, kill_kind: KillFrom,
dfcx_moves: &mut MoveDataFlow) { dfcx_moves: &mut MoveDataFlow) {
// We can only perform kills for paths that refer to a unique location, // 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); let loan_path = self.path_loan_path(path);
if loan_path_is_precise(&loan_path) { if loan_path_is_precise(&loan_path) {
self.each_applicable_move(path, |move_index| { 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()); kill_kind, kill_id, move_index.get());
dfcx_moves.add_kill(kill_kind, kill_id, move_index.get()); dfcx_moves.add_kill(kill_kind, kill_id, move_index.get());
true true
@ -642,7 +633,7 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
} }
pub fn kind_of_move_of_path(&self, pub fn kind_of_move_of_path(&self,
id: ast::NodeId, id: hir::ItemLocalId,
loan_path: &Rc<LoanPath<'tcx>>) loan_path: &Rc<LoanPath<'tcx>>)
-> Option<MoveKind> { -> Option<MoveKind> {
//! Returns the kind of a move of `loan_path` by `id`, if one exists. //! 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 /// 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`. /// that would invalidate a reference to `loan_path` at location `id`.
pub fn each_move_of<F>(&self, pub fn each_move_of<F>(&self,
id: ast::NodeId, id: hir::ItemLocalId,
loan_path: &Rc<LoanPath<'tcx>>, loan_path: &Rc<LoanPath<'tcx>>,
mut f: F) mut f: F)
-> bool where -> 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`. /// Iterates through every assignment to `loan_path` that may have occurred on entry to `id`.
/// `loan_path` must be a single variable. /// `loan_path` must be a single variable.
pub fn each_assignment_of<F>(&self, pub fn each_assignment_of<F>(&self,
id: ast::NodeId, id: hir::ItemLocalId,
loan_path: &Rc<LoanPath<'tcx>>, loan_path: &Rc<LoanPath<'tcx>>,
mut f: F) mut f: F)
-> bool where -> bool where

View file

@ -52,7 +52,7 @@ pub struct DataflowLabeller<'a, 'tcx: 'a> {
impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> { impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> {
fn dataflow_for(&self, e: EntryOrExit, n: &Node<'a>) -> String { fn dataflow_for(&self, e: EntryOrExit, n: &Node<'a>) -> String {
let id = n.1.data.id(); 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 sets = "".to_string();
let mut seen_one = false; let mut seen_one = false;
for &variant in &self.variants { for &variant in &self.variants {

View file

@ -765,7 +765,7 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
let cfg = cfg::CFG::new(tcx, &body); let cfg = cfg::CFG::new(tcx, &body);
let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges; let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
let lcfg = LabelledCFG { let lcfg = LabelledCFG {
hir_map: &tcx.hir, tcx,
cfg: &cfg, cfg: &cfg,
name: format!("node_{}", code.id()), name: format!("node_{}", code.id()),
labelled_edges, labelled_edges,

View file

@ -850,23 +850,25 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
} }
visited.insert(cfg_id); visited.insert(cfg_id);
let node_id = cfg.graph.node_data(idx).id();
// is this a recursive call? // is this a recursive call?
let self_recursive = if node_id != ast::DUMMY_NODE_ID { let local_id = cfg.graph.node_data(idx).id();
match method { 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), Some(ref method) => expr_refers_to_this_method(cx, method, node_id),
None => expr_refers_to_this_fn(cx, id, 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. // add the successors of this node to explore the graph further.
for (_, edge) in cfg.graph.outgoing_edges(idx) { for (_, edge) in cfg.graph.outgoing_edges(idx) {
let target_idx = edge.target(); let target_idx = edge.target();