Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

aatch's cfg revisions, namely to match expressions #22580

Merged
merged 5 commits into from
Feb 24, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1848,7 +1848,7 @@ impl LintPass for UnconditionalRecursion {
continue
}
visited.insert(cfg_id);
let node_id = cfg.graph.node_data(idx).id;
let node_id = cfg.graph.node_data(idx).id();

// is this a recursive call?
if node_id != ast::DUMMY_NODE_ID && checker(cx.tcx, impl_node_id, id, name, node_id) {
Expand Down
242 changes: 143 additions & 99 deletions src/librustc/middle/cfg/construct.rs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/librustc/middle/cfg/graphviz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ impl<'a, 'ast> dot::Labeller<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast> {
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() == ast::DUMMY_NODE_ID {
dot::LabelText::LabelStr("(dummy_node)".into_cow())
} else {
let s = self.ast_map.node_to_string(n.data.id);
let s = self.ast_map.node_to_string(n.data.id());
// left-aligns the lines
let s = replace_newline_with_backslash_l(s);
dot::LabelText::EscStr(s.into_cow())
Expand Down
24 changes: 18 additions & 6 deletions src/librustc/middle/cfg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,33 @@
use middle::graph;
use middle::ty;
use syntax::ast;
use util::nodemap::NodeMap;

mod construct;
pub mod graphviz;

pub struct CFG {
pub exit_map: NodeMap<CFGIndex>,
pub graph: CFGGraph,
pub entry: CFGIndex,
pub exit: CFGIndex,
}

#[derive(Copy)]
pub struct CFGNodeData {
pub id: ast::NodeId
#[derive(Copy, PartialEq)]
pub enum CFGNodeData {
AST(ast::NodeId),
Entry,
Exit,
Dummy,
Unreachable,
}

impl CFGNodeData {
pub fn id(&self) -> ast::NodeId {
if let CFGNodeData::AST(id) = *self {
id
} else {
ast::DUMMY_NODE_ID
}
}
}

pub struct CFGEdgeData {
Expand All @@ -50,6 +62,6 @@ impl CFG {
}

pub fn node_is_reachable(&self, id: ast::NodeId) -> bool {
self.graph.depth_traverse(self.entry).any(|node| node.id == id)
self.graph.depth_traverse(self.entry).any(|node| node.id() == id)
}
}
108 changes: 68 additions & 40 deletions src/librustc/middle/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,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<CFGIndex>,
nodeid_to_index: NodeMap<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
Expand Down Expand Up @@ -88,11 +88,9 @@ struct PropagationContext<'a, 'b: 'a, 'tcx: 'b, O: 'a> {
changed: bool
}

fn to_cfgidx_or_die(id: ast::NodeId, index: &NodeMap<CFGIndex>) -> CFGIndex {
let opt_cfgindex = index.get(&id).cloned();
opt_cfgindex.unwrap_or_else(|| {
panic!("nodeid_to_index does not have entry for NodeId {}", id);
})
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(&[])
}

impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
Expand All @@ -114,9 +112,13 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O
pprust::NodePat(pat) => pat.id
};

if self.has_bitset_for_nodeid(id) {
assert!(self.bits_per_id > 0);
let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
if !self.has_bitset_for_nodeid(id) {
return Ok(());
}

assert!(self.bits_per_id > 0);
let indices = get_cfg_indices(id, &self.nodeid_to_index);
for &cfgidx in indices {
let (start, end) = self.compute_id_range(cfgidx);
let on_entry = &self.on_entry[start.. end];
let entry_str = bits_to_string(on_entry);
Expand Down Expand Up @@ -144,7 +146,7 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O
}

fn build_nodeid_to_index(decl: Option<&ast::FnDecl>,
cfg: &cfg::CFG) -> NodeMap<CFGIndex> {
cfg: &cfg::CFG) -> NodeMap<Vec<CFGIndex>> {
let mut index = NodeMap();

// FIXME (#6298): Would it be better to fold formals from decl
Expand All @@ -157,28 +159,38 @@ fn build_nodeid_to_index(decl: Option<&ast::FnDecl>,
}

cfg.graph.each_node(|node_idx, node| {
if node.data.id != ast::DUMMY_NODE_ID {
index.insert(node.data.id, node_idx);
if let cfg::CFGNodeData::AST(id) = node.data {
match index.entry(id).get() {
Ok(v) => v.push(node_idx),
Err(e) => {
e.insert(vec![node_idx]);
}
}
}
true
});

return index;

fn add_entries_from_fn_decl(index: &mut NodeMap<CFGIndex>,
fn add_entries_from_fn_decl(index: &mut NodeMap<Vec<CFGIndex>>,
decl: &ast::FnDecl,
entry: CFGIndex) {
//! add mappings from the ast nodes for the formal bindings to
//! the entry-node in the graph.
struct Formals<'a> {
entry: CFGIndex,
index: &'a mut NodeMap<CFGIndex>,
index: &'a mut NodeMap<Vec<CFGIndex>>,
}
let mut formals = Formals { entry: entry, index: index };
visit::walk_fn_decl(&mut formals, decl);
impl<'a, 'v> visit::Visitor<'v> for Formals<'a> {
fn visit_pat(&mut self, p: &ast::Pat) {
self.index.insert(p.id, self.entry);
match self.index.entry(p.id).get() {
Ok(v) => v.push(self.entry),
Err(e) => {
e.insert(vec![self.entry]);
}
}
visit::walk_pat(self, p)
}
}
Expand Down Expand Up @@ -230,10 +242,12 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
assert!(self.nodeid_to_index.contains_key(&id));
assert!(self.bits_per_id > 0);

let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
let (start, end) = self.compute_id_range(cfgidx);
let gens = &mut self.gens[start.. end];
set_bit(gens, bit);
let indices = get_cfg_indices(id, &self.nodeid_to_index);
for &cfgidx in indices {
let (start, end) = self.compute_id_range(cfgidx);
let gens = &mut self.gens[start.. end];
set_bit(gens, bit);
}
}

pub fn add_kill(&mut self, id: ast::NodeId, bit: uint) {
Expand All @@ -243,10 +257,12 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
assert!(self.nodeid_to_index.contains_key(&id));
assert!(self.bits_per_id > 0);

let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
let (start, end) = self.compute_id_range(cfgidx);
let kills = &mut self.kills[start.. end];
set_bit(kills, bit);
let indices = get_cfg_indices(id, &self.nodeid_to_index);
for &cfgidx in indices {
let (start, end) = self.compute_id_range(cfgidx);
let kills = &mut self.kills[start.. end];
set_bit(kills, bit);
}
}

fn apply_gen_kill(&self, cfgidx: CFGIndex, bits: &mut [uint]) {
Expand Down Expand Up @@ -279,16 +295,21 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
}


pub fn each_bit_on_entry<F>(&self, id: ast::NodeId, f: F) -> bool where
pub fn each_bit_on_entry<F>(&self, id: ast::NodeId, mut f: F) -> bool where
F: FnMut(uint) -> 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) {
return true;
}
let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
self.each_bit_for_node(Entry, cfgidx, f)
let indices = get_cfg_indices(id, &self.nodeid_to_index);
for &cfgidx in indices {
if !self.each_bit_for_node(Entry, cfgidx, |i| f(i)) {
return false;
}
}
return true;
}

pub fn each_bit_for_node<F>(&self, e: EntryOrExit, cfgidx: CFGIndex, f: F) -> bool where
Expand Down Expand Up @@ -320,7 +341,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
self.each_bit(slice, f)
}

pub fn each_gen_bit<F>(&self, id: ast::NodeId, f: F) -> bool where
pub fn each_gen_bit<F>(&self, id: ast::NodeId, mut f: F) -> bool where
F: FnMut(uint) -> bool,
{
//! Iterates through each bit in the gen set for `id`.
Expand All @@ -334,12 +355,17 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
return true;
}

let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
let (start, end) = self.compute_id_range(cfgidx);
let gens = &self.gens[start.. end];
debug!("{} each_gen_bit(id={}, gens={})",
self.analysis_name, id, bits_to_string(gens));
self.each_bit(gens, f)
let indices = get_cfg_indices(id, &self.nodeid_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={})",
self.analysis_name, id, bits_to_string(gens));
if !self.each_bit(gens, |i| f(i)) {
return false;
}
}
return true;
}

fn each_bit<F>(&self, words: &[uint], mut f: F) -> bool where
Expand Down Expand Up @@ -400,13 +426,15 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {

let mut changed = false;
for &node_id in &edge.data.exiting_scopes {
let opt_cfg_idx = self.nodeid_to_index.get(&node_id).cloned();
let opt_cfg_idx = self.nodeid_to_index.get(&node_id);
match opt_cfg_idx {
Some(cfg_idx) => {
let (start, end) = self.compute_id_range(cfg_idx);
let kills = &self.kills[start.. end];
if bitwise(&mut orig_kills, kills, &Union) {
changed = true;
Some(indices) => {
for &cfg_idx in indices {
let (start, end) = self.compute_id_range(cfg_idx);
let kills = &self.kills[start.. end];
if bitwise(&mut orig_kills, kills, &Union) {
changed = true;
}
}
}
None => {
Expand Down Expand Up @@ -482,7 +510,7 @@ impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> {

cfg.graph.each_node(|node_index, node| {
debug!("DataFlowContext::walk_cfg idx={:?} id={} begin in_out={}",
node_index, node.data.id, bits_to_string(in_out));
node_index, node.data.id(), bits_to_string(in_out));

let (start, end) = self.dfcx.compute_id_range(node_index);

Expand Down
15 changes: 15 additions & 0 deletions src/librustc/middle/pat_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,21 @@ pub fn pat_contains_bindings(dm: &DefMap, pat: &ast::Pat) -> bool {
contains_bindings
}

/// Checks if the pattern contains any patterns that bind something to
/// an ident or wildcard, e.g. `foo`, or `Foo(_)`, `foo @ Bar(..)`,
pub fn pat_contains_bindings_or_wild(dm: &DefMap, pat: &ast::Pat) -> bool {
let mut contains_bindings = false;
walk_pat(pat, |p| {
if pat_is_binding_or_wild(dm, p) {
contains_bindings = true;
false // there's at least one binding/wildcard, can short circuit now.
} else {
true
}
});
contains_bindings
}

pub fn simple_identifier<'a>(pat: &'a ast::Pat) -> Option<&'a ast::Ident> {
match pat.node {
ast::PatIdent(ast::BindByValue(_), ref path1, None) => {
Expand Down
27 changes: 20 additions & 7 deletions src/librustc_borrowck/borrowck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -612,13 +612,26 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
};
let (suggestion, _) =
move_suggestion(param_env, expr_span, expr_ty, ("moved by default", ""));
self.tcx.sess.span_note(
expr_span,
&format!("`{}` moved here{} because it has type `{}`, which is {}",
ol,
moved_lp_msg,
expr_ty.user_string(self.tcx),
suggestion));
// If the two spans are the same, it's because the expression will be evaluated
// multiple times. Avoid printing the same span and adjust the wording so it makes
// more sense that it's from multiple evalutations.
if expr_span == use_span {
self.tcx.sess.note(
&format!("`{}` was previously moved here{} because it has type `{}`, \
which is {}",
ol,
moved_lp_msg,
expr_ty.user_string(self.tcx),
suggestion));
} else {
self.tcx.sess.span_note(
expr_span,
&format!("`{}` moved here{} because it has type `{}`, which is {}",
ol,
moved_lp_msg,
expr_ty.user_string(self.tcx),
suggestion));
}
}

move_data::MovePat => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_borrowck/graphviz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
let id = n.1.data.id();
debug!("dataflow_for({:?}, id={}) {:?}", e, id, self.variants);
let mut sets = "".to_string();
let mut seen_one = false;
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1353,7 +1353,7 @@ fn build_cfg(tcx: &ty::ctxt, id: ast::NodeId) -> (ast::NodeId, Option<cfg::CFG>)
// the clobbering of the existing value in the return slot.
fn has_nested_returns(tcx: &ty::ctxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bool {
for n in cfg.graph.depth_traverse(cfg.entry) {
match tcx.map.find(n.id) {
match tcx.map.find(n.id()) {
Some(ast_map::NodeExpr(ex)) => {
if let ast::ExprRet(Some(ref ret_expr)) = ex.node {
let mut visitor = FindNestedReturn::new();
Expand Down
25 changes: 25 additions & 0 deletions src/test/compile-fail/move-in-guard-1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(box_syntax)]

pub fn main() {
let x = box 1;

let v = (1, 2);

match v {
(1, _) if take(x) => (),
(_, 2) if take(x) => (), //~ ERROR use of moved value: `x`
_ => (),
}
}

fn take<T>(_: T) -> bool { false }
Loading