Skip to content

Commit d7df353

Browse files
committed
Rollup merge of rust-lang#22580 - pnkfelix:guard-pat-cfg2, r=pnkfelix
aatch's cfg revisions, namely to match expressions Revise handling of match expressions so that arms branch to next arm. Update the graphviz tests accordingly. Fixes rust-lang#22073. (Includes regression test for the issue.)
2 parents cfab9cc + 85defff commit d7df353

File tree

14 files changed

+353
-166
lines changed

14 files changed

+353
-166
lines changed

src/librustc/lint/builtin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1856,7 +1856,7 @@ impl LintPass for UnconditionalRecursion {
18561856
continue
18571857
}
18581858
visited.insert(cfg_id);
1859-
let node_id = cfg.graph.node_data(idx).id;
1859+
let node_id = cfg.graph.node_data(idx).id();
18601860

18611861
// is this a recursive call?
18621862
if node_id != ast::DUMMY_NODE_ID && checker(cx.tcx, impl_node_id, id, name, node_id) {

src/librustc/middle/cfg/construct.rs

Lines changed: 143 additions & 99 deletions
Large diffs are not rendered by default.

src/librustc/middle/cfg/graphviz.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ impl<'a, 'ast> dot::Labeller<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast> {
6565
dot::LabelText::LabelStr("entry".into_cow())
6666
} else if i == self.cfg.exit {
6767
dot::LabelText::LabelStr("exit".into_cow())
68-
} else if n.data.id == ast::DUMMY_NODE_ID {
68+
} else if n.data.id() == ast::DUMMY_NODE_ID {
6969
dot::LabelText::LabelStr("(dummy_node)".into_cow())
7070
} else {
71-
let s = self.ast_map.node_to_string(n.data.id);
71+
let s = self.ast_map.node_to_string(n.data.id());
7272
// left-aligns the lines
7373
let s = replace_newline_with_backslash_l(s);
7474
dot::LabelText::EscStr(s.into_cow())

src/librustc/middle/cfg/mod.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,33 @@
1414
use middle::graph;
1515
use middle::ty;
1616
use syntax::ast;
17-
use util::nodemap::NodeMap;
1817

1918
mod construct;
2019
pub mod graphviz;
2120

2221
pub struct CFG {
23-
pub exit_map: NodeMap<CFGIndex>,
2422
pub graph: CFGGraph,
2523
pub entry: CFGIndex,
2624
pub exit: CFGIndex,
2725
}
2826

29-
#[derive(Copy)]
30-
pub struct CFGNodeData {
31-
pub id: ast::NodeId
27+
#[derive(Copy, PartialEq)]
28+
pub enum CFGNodeData {
29+
AST(ast::NodeId),
30+
Entry,
31+
Exit,
32+
Dummy,
33+
Unreachable,
34+
}
35+
36+
impl CFGNodeData {
37+
pub fn id(&self) -> ast::NodeId {
38+
if let CFGNodeData::AST(id) = *self {
39+
id
40+
} else {
41+
ast::DUMMY_NODE_ID
42+
}
43+
}
3244
}
3345

3446
pub struct CFGEdgeData {
@@ -50,6 +62,6 @@ impl CFG {
5062
}
5163

5264
pub fn node_is_reachable(&self, id: ast::NodeId) -> bool {
53-
self.graph.depth_traverse(self.entry).any(|node| node.id == id)
65+
self.graph.depth_traverse(self.entry).any(|node| node.id() == id)
5466
}
5567
}

src/librustc/middle/dataflow.rs

Lines changed: 68 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub struct DataFlowContext<'a, 'tcx: 'a, O> {
5353

5454
// mapping from node to cfg node index
5555
// FIXME (#6298): Shouldn't this go with CFG?
56-
nodeid_to_index: NodeMap<CFGIndex>,
56+
nodeid_to_index: NodeMap<Vec<CFGIndex>>,
5757

5858
// Bit sets per cfg node. The following three fields (`gens`, `kills`,
5959
// and `on_entry`) all have the same structure. For each id in
@@ -88,11 +88,9 @@ struct PropagationContext<'a, 'b: 'a, 'tcx: 'b, O: 'a> {
8888
changed: bool
8989
}
9090

91-
fn to_cfgidx_or_die(id: ast::NodeId, index: &NodeMap<CFGIndex>) -> CFGIndex {
92-
let opt_cfgindex = index.get(&id).cloned();
93-
opt_cfgindex.unwrap_or_else(|| {
94-
panic!("nodeid_to_index does not have entry for NodeId {}", id);
95-
})
91+
fn get_cfg_indices<'a>(id: ast::NodeId, index: &'a NodeMap<Vec<CFGIndex>>) -> &'a [CFGIndex] {
92+
let opt_indices = index.get(&id);
93+
opt_indices.map(|v| &v[..]).unwrap_or(&[])
9694
}
9795

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

117-
if self.has_bitset_for_nodeid(id) {
118-
assert!(self.bits_per_id > 0);
119-
let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
115+
if !self.has_bitset_for_nodeid(id) {
116+
return Ok(());
117+
}
118+
119+
assert!(self.bits_per_id > 0);
120+
let indices = get_cfg_indices(id, &self.nodeid_to_index);
121+
for &cfgidx in indices {
120122
let (start, end) = self.compute_id_range(cfgidx);
121123
let on_entry = &self.on_entry[start.. end];
122124
let entry_str = bits_to_string(on_entry);
@@ -144,7 +146,7 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O
144146
}
145147

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

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

159161
cfg.graph.each_node(|node_idx, node| {
160-
if node.data.id != ast::DUMMY_NODE_ID {
161-
index.insert(node.data.id, node_idx);
162+
if let cfg::CFGNodeData::AST(id) = node.data {
163+
match index.entry(id).get() {
164+
Ok(v) => v.push(node_idx),
165+
Err(e) => {
166+
e.insert(vec![node_idx]);
167+
}
168+
}
162169
}
163170
true
164171
});
165172

166173
return index;
167174

168-
fn add_entries_from_fn_decl(index: &mut NodeMap<CFGIndex>,
175+
fn add_entries_from_fn_decl(index: &mut NodeMap<Vec<CFGIndex>>,
169176
decl: &ast::FnDecl,
170177
entry: CFGIndex) {
171178
//! add mappings from the ast nodes for the formal bindings to
172179
//! the entry-node in the graph.
173180
struct Formals<'a> {
174181
entry: CFGIndex,
175-
index: &'a mut NodeMap<CFGIndex>,
182+
index: &'a mut NodeMap<Vec<CFGIndex>>,
176183
}
177184
let mut formals = Formals { entry: entry, index: index };
178185
visit::walk_fn_decl(&mut formals, decl);
179186
impl<'a, 'v> visit::Visitor<'v> for Formals<'a> {
180187
fn visit_pat(&mut self, p: &ast::Pat) {
181-
self.index.insert(p.id, self.entry);
188+
match self.index.entry(p.id).get() {
189+
Ok(v) => v.push(self.entry),
190+
Err(e) => {
191+
e.insert(vec![self.entry]);
192+
}
193+
}
182194
visit::walk_pat(self, p)
183195
}
184196
}
@@ -230,10 +242,12 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
230242
assert!(self.nodeid_to_index.contains_key(&id));
231243
assert!(self.bits_per_id > 0);
232244

233-
let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
234-
let (start, end) = self.compute_id_range(cfgidx);
235-
let gens = &mut self.gens[start.. end];
236-
set_bit(gens, bit);
245+
let indices = get_cfg_indices(id, &self.nodeid_to_index);
246+
for &cfgidx in indices {
247+
let (start, end) = self.compute_id_range(cfgidx);
248+
let gens = &mut self.gens[start.. end];
249+
set_bit(gens, bit);
250+
}
237251
}
238252

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

246-
let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
247-
let (start, end) = self.compute_id_range(cfgidx);
248-
let kills = &mut self.kills[start.. end];
249-
set_bit(kills, bit);
260+
let indices = get_cfg_indices(id, &self.nodeid_to_index);
261+
for &cfgidx in indices {
262+
let (start, end) = self.compute_id_range(cfgidx);
263+
let kills = &mut self.kills[start.. end];
264+
set_bit(kills, bit);
265+
}
250266
}
251267

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

281297

282-
pub fn each_bit_on_entry<F>(&self, id: ast::NodeId, f: F) -> bool where
298+
pub fn each_bit_on_entry<F>(&self, id: ast::NodeId, mut f: F) -> bool where
283299
F: FnMut(uint) -> bool,
284300
{
285301
//! Iterates through each bit that is set on entry to `id`.
286302
//! Only useful after `propagate()` has been called.
287303
if !self.has_bitset_for_nodeid(id) {
288304
return true;
289305
}
290-
let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
291-
self.each_bit_for_node(Entry, cfgidx, f)
306+
let indices = get_cfg_indices(id, &self.nodeid_to_index);
307+
for &cfgidx in indices {
308+
if !self.each_bit_for_node(Entry, cfgidx, |i| f(i)) {
309+
return false;
310+
}
311+
}
312+
return true;
292313
}
293314

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

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

337-
let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index);
338-
let (start, end) = self.compute_id_range(cfgidx);
339-
let gens = &self.gens[start.. end];
340-
debug!("{} each_gen_bit(id={}, gens={})",
341-
self.analysis_name, id, bits_to_string(gens));
342-
self.each_bit(gens, f)
358+
let indices = get_cfg_indices(id, &self.nodeid_to_index);
359+
for &cfgidx in indices {
360+
let (start, end) = self.compute_id_range(cfgidx);
361+
let gens = &self.gens[start.. end];
362+
debug!("{} each_gen_bit(id={}, gens={})",
363+
self.analysis_name, id, bits_to_string(gens));
364+
if !self.each_bit(gens, |i| f(i)) {
365+
return false;
366+
}
367+
}
368+
return true;
343369
}
344370

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

401427
let mut changed = false;
402428
for &node_id in &edge.data.exiting_scopes {
403-
let opt_cfg_idx = self.nodeid_to_index.get(&node_id).cloned();
429+
let opt_cfg_idx = self.nodeid_to_index.get(&node_id);
404430
match opt_cfg_idx {
405-
Some(cfg_idx) => {
406-
let (start, end) = self.compute_id_range(cfg_idx);
407-
let kills = &self.kills[start.. end];
408-
if bitwise(&mut orig_kills, kills, &Union) {
409-
changed = true;
431+
Some(indices) => {
432+
for &cfg_idx in indices {
433+
let (start, end) = self.compute_id_range(cfg_idx);
434+
let kills = &self.kills[start.. end];
435+
if bitwise(&mut orig_kills, kills, &Union) {
436+
changed = true;
437+
}
410438
}
411439
}
412440
None => {
@@ -482,7 +510,7 @@ impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> {
482510

483511
cfg.graph.each_node(|node_index, node| {
484512
debug!("DataFlowContext::walk_cfg idx={:?} id={} begin in_out={}",
485-
node_index, node.data.id, bits_to_string(in_out));
513+
node_index, node.data.id(), bits_to_string(in_out));
486514

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

src/librustc/middle/pat_util.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,21 @@ pub fn pat_contains_bindings(dm: &DefMap, pat: &ast::Pat) -> bool {
119119
contains_bindings
120120
}
121121

122+
/// Checks if the pattern contains any patterns that bind something to
123+
/// an ident or wildcard, e.g. `foo`, or `Foo(_)`, `foo @ Bar(..)`,
124+
pub fn pat_contains_bindings_or_wild(dm: &DefMap, pat: &ast::Pat) -> bool {
125+
let mut contains_bindings = false;
126+
walk_pat(pat, |p| {
127+
if pat_is_binding_or_wild(dm, p) {
128+
contains_bindings = true;
129+
false // there's at least one binding/wildcard, can short circuit now.
130+
} else {
131+
true
132+
}
133+
});
134+
contains_bindings
135+
}
136+
122137
pub fn simple_identifier<'a>(pat: &'a ast::Pat) -> Option<&'a ast::Ident> {
123138
match pat.node {
124139
ast::PatIdent(ast::BindByValue(_), ref path1, None) => {

src/librustc_borrowck/borrowck/mod.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -612,13 +612,26 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
612612
};
613613
let (suggestion, _) =
614614
move_suggestion(param_env, expr_span, expr_ty, ("moved by default", ""));
615-
self.tcx.sess.span_note(
616-
expr_span,
617-
&format!("`{}` moved here{} because it has type `{}`, which is {}",
618-
ol,
619-
moved_lp_msg,
620-
expr_ty.user_string(self.tcx),
621-
suggestion));
615+
// If the two spans are the same, it's because the expression will be evaluated
616+
// multiple times. Avoid printing the same span and adjust the wording so it makes
617+
// more sense that it's from multiple evalutations.
618+
if expr_span == use_span {
619+
self.tcx.sess.note(
620+
&format!("`{}` was previously moved here{} because it has type `{}`, \
621+
which is {}",
622+
ol,
623+
moved_lp_msg,
624+
expr_ty.user_string(self.tcx),
625+
suggestion));
626+
} else {
627+
self.tcx.sess.span_note(
628+
expr_span,
629+
&format!("`{}` moved here{} because it has type `{}`, which is {}",
630+
ol,
631+
moved_lp_msg,
632+
expr_ty.user_string(self.tcx),
633+
suggestion));
634+
}
622635
}
623636

624637
move_data::MovePat => {

src/librustc_borrowck/graphviz.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub struct DataflowLabeller<'a, 'tcx: 'a> {
5252

5353
impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> {
5454
fn dataflow_for(&self, e: EntryOrExit, n: &Node<'a>) -> String {
55-
let id = n.1.data.id;
55+
let id = n.1.data.id();
5656
debug!("dataflow_for({:?}, id={}) {:?}", e, id, self.variants);
5757
let mut sets = "".to_string();
5858
let mut seen_one = false;

src/librustc_trans/trans/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1353,7 +1353,7 @@ fn build_cfg(tcx: &ty::ctxt, id: ast::NodeId) -> (ast::NodeId, Option<cfg::CFG>)
13531353
// the clobbering of the existing value in the return slot.
13541354
fn has_nested_returns(tcx: &ty::ctxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bool {
13551355
for n in cfg.graph.depth_traverse(cfg.entry) {
1356-
match tcx.map.find(n.id) {
1356+
match tcx.map.find(n.id()) {
13571357
Some(ast_map::NodeExpr(ex)) => {
13581358
if let ast::ExprRet(Some(ref ret_expr)) = ex.node {
13591359
let mut visitor = FindNestedReturn::new();
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(box_syntax)]
12+
13+
pub fn main() {
14+
let x = box 1;
15+
16+
let v = (1, 2);
17+
18+
match v {
19+
(1, _) if take(x) => (),
20+
(_, 2) if take(x) => (), //~ ERROR use of moved value: `x`
21+
_ => (),
22+
}
23+
}
24+
25+
fn take<T>(_: T) -> bool { false }

0 commit comments

Comments
 (0)