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