rustc: use hir::ItemLocalId instead of ast::NodeId in CFG.
This commit is contained in:
parent
45d31e7310
commit
28ddd7a4ef
13 changed files with 249 additions and 216 deletions
|
@ -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,
|
||||||
});
|
});
|
||||||
|
|
|
@ -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[..]));
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()),
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)"),
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Add table
Reference in a new issue