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

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

View File

@ -12,7 +12,6 @@ use rustc_data_structures::graph;
use cfg::*;
use 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,
});

View File

@ -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[..]));

View File

@ -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)
}

View File

@ -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()),
};

View File

@ -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);

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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)"),
};

View File

@ -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

View File

@ -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 {

View File

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

View File

@ -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();