Skip to content

Commit ebd8ba2

Browse files
committed
Extend rustc::middle::dataflow to allow filtering the kills from flow-exits.
Fix borrowck analysis so that it will not treat a break that pops through an assignment `x = { ... break; ... }` as a kill of the "moved-out" bit for `x`. Fix #24267.
1 parent 9539627 commit ebd8ba2

File tree

3 files changed

+57
-8
lines changed

3 files changed

+57
-8
lines changed

src/librustc/middle/dataflow.rs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,13 @@ fn build_nodeid_to_index(decl: Option<&ast::FnDecl>,
187187
}
188188
}
189189

190+
pub struct FlowExit {
191+
pub breaking_node: CFGIndex,
192+
pub exiting_scope: (ast::NodeId, CFGIndex),
193+
}
194+
195+
pub enum FlowExitEffect { AddKills, IgnoreKills }
196+
190197
impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
191198
pub fn new(tcx: &'a ty::ctxt<'tcx>,
192199
analysis_name: &'static str,
@@ -393,7 +400,9 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
393400
return true;
394401
}
395402

396-
pub fn add_kills_from_flow_exits(&mut self, cfg: &cfg::CFG) {
403+
pub fn add_kills_from_flow_exits<P>(&mut self, cfg: &cfg::CFG, mut p:P)
404+
where P: FnMut(FlowExit) -> FlowExitEffect
405+
{
397406
//! Whenever you have a `break` or `continue` statement, flow
398407
//! exits through any number of enclosing scopes on its way to
399408
//! the new destination. This function infers the kill bits of
@@ -402,6 +411,11 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
402411
//!
403412
//! This is usually called (if it is called at all), after
404413
//! all add_gen and add_kill calls, but before propagate.
414+
//!
415+
//! The callback predicate `p(b, e)` is invoked on each node
416+
//! `e` that has been registered as an `exiting_scope` for a
417+
//! given control-breaking node `b`, to determine whether to
418+
//! include the associated kill-effects or not.
405419
406420
debug!("{} add_kills_from_flow_exits", self.analysis_name);
407421
if self.bits_per_id == 0 {
@@ -420,10 +434,21 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
420434
match opt_cfg_idx {
421435
Some(indices) => {
422436
for &cfg_idx in indices {
423-
let (start, end) = self.compute_id_range(cfg_idx);
424-
let kills = &self.kills[start.. end];
425-
if bitwise(&mut orig_kills, kills, &Union) {
426-
changed = true;
437+
match p(FlowExit {
438+
breaking_node: flow_exit,
439+
exiting_scope: (node_id, cfg_idx) }) {
440+
FlowExitEffect::IgnoreKills => continue,
441+
FlowExitEffect::AddKills => {
442+
let (start, end) = self.compute_id_range(cfg_idx);
443+
let kills = &self.kills[start.. end];
444+
if bitwise(&mut orig_kills, kills, &Union) {
445+
debug!("scope exits: scope id={} \
446+
(node={:?} of {:?}) added killset: {}",
447+
node_id, cfg_idx, indices,
448+
bits_to_string(kills));
449+
changed = true;
450+
}
451+
}
427452
}
428453
}
429454
}

src/librustc_borrowck/borrowck/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use rustc::middle::cfg;
2424
use rustc::middle::dataflow::DataFlowContext;
2525
use rustc::middle::dataflow::BitwiseOperator;
2626
use rustc::middle::dataflow::DataFlowOperator;
27+
use rustc::middle::dataflow::FlowExitEffect;
2728
use rustc::middle::expr_use_visitor as euv;
2829
use rustc::middle::mem_categorization as mc;
2930
use rustc::middle::region;
@@ -169,7 +170,9 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
169170
loan_dfcx.add_gen(loan.gen_scope.node_id(), loan_idx);
170171
loan_dfcx.add_kill(loan.kill_scope.node_id(), loan_idx);
171172
}
172-
loan_dfcx.add_kills_from_flow_exits(cfg);
173+
loan_dfcx.add_kills_from_flow_exits(cfg, |_flow_exit| {
174+
FlowExitEffect::AddKills
175+
});
173176
loan_dfcx.propagate(cfg, body);
174177

175178
let flowed_moves = move_data::FlowedMoveData::new(move_data,

src/librustc_borrowck/borrowck/move_data.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc::middle::cfg;
1818
use rustc::middle::dataflow::DataFlowContext;
1919
use rustc::middle::dataflow::BitwiseOperator;
2020
use rustc::middle::dataflow::DataFlowOperator;
21+
use rustc::middle::dataflow::FlowExitEffect;
2122
use rustc::middle::expr_use_visitor as euv;
2223
use rustc::middle::ty;
2324
use rustc::util::nodemap::{FnvHashMap, NodeSet};
@@ -59,6 +60,9 @@ pub struct MoveData<'tcx> {
5960
/// Assignments to a variable or path, like `x = foo`, but not `x += foo`.
6061
pub assignee_ids: RefCell<NodeSet>,
6162

63+
/// AST node ids for move entries that have kind `Declared`.
64+
pub declared_ids: RefCell<NodeSet>,
65+
6266
/// Path-fragments from moves in to or out of parts of structured data.
6367
pub fragments: RefCell<fragments::FragmentSets>,
6468
}
@@ -216,6 +220,7 @@ impl<'tcx> MoveData<'tcx> {
216220
var_assignments: RefCell::new(Vec::new()),
217221
variant_matches: RefCell::new(Vec::new()),
218222
assignee_ids: RefCell::new(NodeSet()),
223+
declared_ids: RefCell::new(NodeSet()),
219224
fragments: RefCell::new(fragments::FragmentSets::new()),
220225
}
221226
}
@@ -376,6 +381,10 @@ impl<'tcx> MoveData<'tcx> {
376381
let next_move = self.path_first_move(path_index);
377382
self.set_path_first_move(path_index, move_index);
378383

384+
if kind == MoveKind::Declared {
385+
self.declared_ids.borrow_mut().insert(id);
386+
}
387+
379388
self.moves.borrow_mut().push(Move {
380389
path: path_index,
381390
id: id,
@@ -614,8 +623,20 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> {
614623
&mut dfcx_moves,
615624
&mut dfcx_assign);
616625

617-
dfcx_moves.add_kills_from_flow_exits(cfg);
618-
dfcx_assign.add_kills_from_flow_exits(cfg);
626+
dfcx_moves.add_kills_from_flow_exits(cfg, |flow_exit| {
627+
// A `let x = { ... break ...};` statement should kill the
628+
// move-bit for `x`, but a `x = { ... break; ... };
629+
// statement should leave it alone (#24267).
630+
let (exiting_scope_id, _) = flow_exit.exiting_scope;
631+
if move_data.declared_ids.borrow().contains(&exiting_scope_id) {
632+
FlowExitEffect::AddKills
633+
} else {
634+
FlowExitEffect::IgnoreKills
635+
}
636+
});
637+
dfcx_assign.add_kills_from_flow_exits(cfg, |_flow_exit| {
638+
FlowExitEffect::AddKills
639+
});
619640

620641
dfcx_moves.propagate(cfg, body);
621642
dfcx_assign.propagate(cfg, body);

0 commit comments

Comments
 (0)