Skip to content

Commit 4416b32

Browse files
committed
auto merge of #14873 : pnkfelix/rust/fsk-dataflow-revisions, r=nikomatsakis
Fix #6298. Fix #13767. This also includes some drive by fixes for some other issues, noted in the commits. I still need to integrate regression tests for some cases that I noticed were missing from our unit test suite (i.e. things that compiling rustc exposes that should have been exposed when doing `make check-stage1`). So do not land this yet, until I get the chance to add those tests. I just wanted to get the review process started soon, since this has been long in the coming.
2 parents 78cb2f5 + 4c2a8bb commit 4416b32

23 files changed

+984
-646
lines changed

src/librustc/middle/borrowck/check_loans.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ impl<'a> CheckLoanCtxt<'a> {
242242
let mut loan_path = loan_path;
243243
loop {
244244
match *loan_path {
245-
LpVar(_) => {
245+
LpVar(_) | LpUpvar(_) => {
246246
break;
247247
}
248248
LpExtend(ref lp_base, _, _) => {
@@ -632,7 +632,7 @@ impl<'a> CheckLoanCtxt<'a> {
632632
*/
633633

634634
match **lp {
635-
LpVar(_) => {
635+
LpVar(_) | LpUpvar(_) => {
636636
// assigning to `x` does not require that `x` is initialized
637637
}
638638
LpExtend(ref lp_base, _, LpInterior(_)) => {

src/librustc/middle/borrowck/doc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,7 @@ The borrow checker is also in charge of ensuring that:
948948
949949
These are two separate dataflow analyses built on the same
950950
framework. Let's look at checking that memory is initialized first;
951-
the checking of immutable local variabe assignments works in a very
951+
the checking of immutable local variable assignments works in a very
952952
similar way.
953953
954954
To track the initialization of memory, we actually track all the

src/librustc/middle/borrowck/gather_loans/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,8 @@ impl<'a> GatherLoanCtxt<'a> {
395395
//! from a local variable, mark the mutability decl as necessary.
396396
397397
match *loan_path {
398-
LpVar(local_id) => {
398+
LpVar(local_id) |
399+
LpUpvar(ty::UpvarId{ var_id: local_id, closure_expr_id: _ }) => {
399400
self.tcx().used_mut_nodes.borrow_mut().insert(local_id);
400401
}
401402
LpExtend(ref base, mc::McInherited, _) => {
@@ -445,8 +446,8 @@ impl<'a> GatherLoanCtxt<'a> {
445446
//! with immutable `&` pointers, because borrows of such pointers
446447
//! do not require restrictions and hence do not cause a loan.
447448
449+
let lexical_scope = lp.kill_scope(self.bccx.tcx);
448450
let rm = &self.bccx.tcx.region_maps;
449-
let lexical_scope = rm.var_scope(lp.node_id());
450451
if rm.is_subscope_of(lexical_scope, loan_scope) {
451452
lexical_scope
452453
} else {

src/librustc/middle/borrowck/gather_loans/restrictions.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,23 @@ impl<'a> RestrictionsContext<'a> {
6767
}
6868

6969
mc::cat_local(local_id) |
70-
mc::cat_arg(local_id) |
71-
mc::cat_upvar(ty::UpvarId {var_id: local_id, ..}, _) => {
72-
// R-Variable
70+
mc::cat_arg(local_id) => {
71+
// R-Variable, locally declared
7372
let lp = Rc::new(LpVar(local_id));
7473
SafeIf(lp.clone(), vec!(lp))
7574
}
7675

76+
mc::cat_upvar(upvar_id, _) => {
77+
// R-Variable, captured into closure
78+
let lp = Rc::new(LpUpvar(upvar_id));
79+
SafeIf(lp.clone(), vec!(lp))
80+
}
81+
82+
mc::cat_copied_upvar(..) => {
83+
// FIXME(#2152) allow mutation of upvars
84+
Safe
85+
}
86+
7787
mc::cat_downcast(cmt_base) => {
7888
// When we borrow the interior of an enum, we have to
7989
// ensure the enum itself is not mutated, because that
@@ -107,7 +117,6 @@ impl<'a> RestrictionsContext<'a> {
107117
self.extend(result, cmt.mutbl, LpDeref(pk))
108118
}
109119

110-
mc::cat_copied_upvar(..) | // FIXME(#2152) allow mutation of upvars
111120
mc::cat_static_item(..) => {
112121
Safe
113122
}

src/librustc/middle/borrowck/mod.rs

+53-13
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212

1313
#![allow(non_camel_case_types)]
1414

15+
use middle::cfg;
1516
use middle::dataflow::DataFlowContext;
17+
use middle::dataflow::BitwiseOperator;
1618
use middle::dataflow::DataFlowOperator;
1719
use middle::def;
1820
use euv = middle::expr_use_visitor;
@@ -126,20 +128,28 @@ fn borrowck_fn(this: &mut BorrowckCtxt,
126128
let id_range = ast_util::compute_id_range_for_fn_body(fk, decl, body, sp, id);
127129
let (all_loans, move_data) =
128130
gather_loans::gather_loans_in_fn(this, decl, body);
131+
let cfg = cfg::CFG::new(this.tcx, body);
132+
129133
let mut loan_dfcx =
130134
DataFlowContext::new(this.tcx,
135+
"borrowck",
136+
Some(decl),
137+
&cfg,
131138
LoanDataFlowOperator,
132139
id_range,
133140
all_loans.len());
134141
for (loan_idx, loan) in all_loans.iter().enumerate() {
135142
loan_dfcx.add_gen(loan.gen_scope, loan_idx);
136143
loan_dfcx.add_kill(loan.kill_scope, loan_idx);
137144
}
138-
loan_dfcx.propagate(body);
145+
loan_dfcx.add_kills_from_flow_exits(&cfg);
146+
loan_dfcx.propagate(&cfg, body);
139147

140148
let flowed_moves = move_data::FlowedMoveData::new(move_data,
141149
this.tcx,
150+
&cfg,
142151
id_range,
152+
decl,
143153
body);
144154

145155
check_loans::check_loans(this, &loan_dfcx, flowed_moves,
@@ -191,6 +201,7 @@ pub struct Loan {
191201
#[deriving(PartialEq, Eq, Hash)]
192202
pub enum LoanPath {
193203
LpVar(ast::NodeId), // `x` in doc.rs
204+
LpUpvar(ty::UpvarId), // `x` captured by-value into closure
194205
LpExtend(Rc<LoanPath>, mc::MutabilityCategory, LoanPathElem)
195206
}
196207

@@ -200,11 +211,25 @@ pub enum LoanPathElem {
200211
LpInterior(mc::InteriorKind) // `LV.f` in doc.rs
201212
}
202213

214+
pub fn closure_to_block(closure_id: ast::NodeId,
215+
tcx: &ty::ctxt) -> ast::NodeId {
216+
match tcx.map.get(closure_id) {
217+
ast_map::NodeExpr(expr) => match expr.node {
218+
ast::ExprProc(_decl, block) |
219+
ast::ExprFnBlock(_decl, block) => { block.id }
220+
_ => fail!("encountered non-closure id: {}", closure_id)
221+
},
222+
_ => fail!("encountered non-expr id: {}", closure_id)
223+
}
224+
}
225+
203226
impl LoanPath {
204-
pub fn node_id(&self) -> ast::NodeId {
227+
pub fn kill_scope(&self, tcx: &ty::ctxt) -> ast::NodeId {
205228
match *self {
206-
LpVar(local_id) => local_id,
207-
LpExtend(ref base, _, _) => base.node_id()
229+
LpVar(local_id) => tcx.region_maps.var_scope(local_id),
230+
LpUpvar(upvar_id) =>
231+
closure_to_block(upvar_id.closure_expr_id, tcx),
232+
LpExtend(ref base, _, _) => base.kill_scope(tcx),
208233
}
209234
}
210235
}
@@ -224,12 +249,18 @@ pub fn opt_loan_path(cmt: &mc::cmt) -> Option<Rc<LoanPath>> {
224249
}
225250

226251
mc::cat_local(id) |
227-
mc::cat_arg(id) |
228-
mc::cat_copied_upvar(mc::CopiedUpvar { upvar_id: id, .. }) |
229-
mc::cat_upvar(ty::UpvarId {var_id: id, ..}, _) => {
252+
mc::cat_arg(id) => {
230253
Some(Rc::new(LpVar(id)))
231254
}
232255

256+
mc::cat_upvar(ty::UpvarId {var_id: id, closure_expr_id: proc_id}, _) |
257+
mc::cat_copied_upvar(mc::CopiedUpvar { upvar_id: id,
258+
onceness: _,
259+
capturing_proc: proc_id }) => {
260+
let upvar_id = ty::UpvarId{ var_id: id, closure_expr_id: proc_id };
261+
Some(Rc::new(LpUpvar(upvar_id)))
262+
}
263+
233264
mc::cat_deref(ref cmt_base, _, pk) => {
234265
opt_loan_path(cmt_base).map(|lp| {
235266
Rc::new(LpExtend(lp, cmt.mutbl, LpDeref(pk)))
@@ -683,6 +714,7 @@ impl<'a> BorrowckCtxt<'a> {
683714
loan_path: &LoanPath,
684715
out: &mut String) {
685716
match *loan_path {
717+
LpUpvar(ty::UpvarId{ var_id: id, closure_expr_id: _ }) |
686718
LpVar(id) => {
687719
out.push_str(ty::local_var_name_str(self.tcx, id).get());
688720
}
@@ -724,7 +756,7 @@ impl<'a> BorrowckCtxt<'a> {
724756
self.append_autoderefd_loan_path_to_str(&**lp_base, out)
725757
}
726758

727-
LpVar(..) | LpExtend(_, _, LpInterior(..)) => {
759+
LpVar(..) | LpUpvar(..) | LpExtend(_, _, LpInterior(..)) => {
728760
self.append_loan_path_to_str(loan_path, out)
729761
}
730762
}
@@ -753,15 +785,17 @@ fn is_statement_scope(tcx: &ty::ctxt, region: ty::Region) -> bool {
753785
}
754786
}
755787

756-
impl DataFlowOperator for LoanDataFlowOperator {
788+
impl BitwiseOperator for LoanDataFlowOperator {
757789
#[inline]
758-
fn initial_value(&self) -> bool {
759-
false // no loans in scope by default
790+
fn join(&self, succ: uint, pred: uint) -> uint {
791+
succ | pred // loans from both preds are in scope
760792
}
793+
}
761794

795+
impl DataFlowOperator for LoanDataFlowOperator {
762796
#[inline]
763-
fn join(&self, succ: uint, pred: uint) -> uint {
764-
succ | pred // loans from both preds are in scope
797+
fn initial_value(&self) -> bool {
798+
false // no loans in scope by default
765799
}
766800
}
767801

@@ -784,6 +818,12 @@ impl Repr for LoanPath {
784818
(format!("$({})", tcx.map.node_to_str(id))).to_string()
785819
}
786820

821+
&LpUpvar(ty::UpvarId{ var_id, closure_expr_id }) => {
822+
let s = tcx.map.node_to_str(var_id);
823+
let s = format!("$({} captured by id={})", s, closure_expr_id);
824+
s.to_string()
825+
}
826+
787827
&LpExtend(ref lp, _, LpDeref(_)) => {
788828
(format!("{}.*", lp.repr(tcx))).to_string()
789829
}

src/librustc/middle/borrowck/move_data.rs

+35-9
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ use std::rc::Rc;
2020
use std::uint;
2121
use std::collections::{HashMap, HashSet};
2222
use middle::borrowck::*;
23+
use middle::cfg;
2324
use middle::dataflow::DataFlowContext;
25+
use middle::dataflow::BitwiseOperator;
2426
use middle::dataflow::DataFlowOperator;
2527
use euv = middle::expr_use_visitor;
2628
use middle::ty;
@@ -229,7 +231,7 @@ impl MoveData {
229231
}
230232

231233
let index = match *lp {
232-
LpVar(..) => {
234+
LpVar(..) | LpUpvar(..) => {
233235
let index = MovePathIndex(self.paths.borrow().len());
234236

235237
self.paths.borrow_mut().push(MovePath {
@@ -300,7 +302,7 @@ impl MoveData {
300302
}
301303
None => {
302304
match **lp {
303-
LpVar(..) => { }
305+
LpVar(..) | LpUpvar(..) => { }
304306
LpExtend(ref b, _, _) => {
305307
self.add_existing_base_paths(b, result);
306308
}
@@ -416,6 +418,11 @@ impl MoveData {
416418
let path = *self.path_map.borrow().get(&path.loan_path);
417419
self.kill_moves(path, kill_id, dfcx_moves);
418420
}
421+
LpUpvar(ty::UpvarId { var_id: _, closure_expr_id }) => {
422+
let kill_id = closure_to_block(closure_expr_id, tcx);
423+
let path = *self.path_map.borrow().get(&path.loan_path);
424+
self.kill_moves(path, kill_id, dfcx_moves);
425+
}
419426
LpExtend(..) => {}
420427
}
421428
}
@@ -428,6 +435,10 @@ impl MoveData {
428435
let kill_id = tcx.region_maps.var_scope(id);
429436
dfcx_assign.add_kill(kill_id, assignment_index);
430437
}
438+
LpUpvar(ty::UpvarId { var_id: _, closure_expr_id }) => {
439+
let kill_id = closure_to_block(closure_expr_id, tcx);
440+
dfcx_assign.add_kill(kill_id, assignment_index);
441+
}
431442
LpExtend(..) => {
432443
tcx.sess.bug("var assignment for non var path");
433444
}
@@ -499,22 +510,33 @@ impl MoveData {
499510
impl<'a> FlowedMoveData<'a> {
500511
pub fn new(move_data: MoveData,
501512
tcx: &'a ty::ctxt,
513+
cfg: &'a cfg::CFG,
502514
id_range: ast_util::IdRange,
515+
decl: &ast::FnDecl,
503516
body: &ast::Block)
504517
-> FlowedMoveData<'a> {
505518
let mut dfcx_moves =
506519
DataFlowContext::new(tcx,
520+
"flowed_move_data_moves",
521+
Some(decl),
522+
cfg,
507523
MoveDataFlowOperator,
508524
id_range,
509525
move_data.moves.borrow().len());
510526
let mut dfcx_assign =
511527
DataFlowContext::new(tcx,
528+
"flowed_move_data_assigns",
529+
Some(decl),
530+
cfg,
512531
AssignDataFlowOperator,
513532
id_range,
514533
move_data.var_assignments.borrow().len());
515534
move_data.add_gen_kills(tcx, &mut dfcx_moves, &mut dfcx_assign);
516-
dfcx_moves.propagate(body);
517-
dfcx_assign.propagate(body);
535+
dfcx_moves.add_kills_from_flow_exits(cfg);
536+
dfcx_assign.add_kills_from_flow_exits(cfg);
537+
dfcx_moves.propagate(cfg, body);
538+
dfcx_assign.propagate(cfg, body);
539+
518540
FlowedMoveData {
519541
move_data: move_data,
520542
dfcx_moves: dfcx_moves,
@@ -659,12 +681,21 @@ impl<'a> FlowedMoveData<'a> {
659681
}
660682
}
661683

684+
impl BitwiseOperator for MoveDataFlowOperator {
685+
#[inline]
686+
fn join(&self, succ: uint, pred: uint) -> uint {
687+
succ | pred // moves from both preds are in scope
688+
}
689+
}
690+
662691
impl DataFlowOperator for MoveDataFlowOperator {
663692
#[inline]
664693
fn initial_value(&self) -> bool {
665694
false // no loans in scope by default
666695
}
696+
}
667697

698+
impl BitwiseOperator for AssignDataFlowOperator {
668699
#[inline]
669700
fn join(&self, succ: uint, pred: uint) -> uint {
670701
succ | pred // moves from both preds are in scope
@@ -676,9 +707,4 @@ impl DataFlowOperator for AssignDataFlowOperator {
676707
fn initial_value(&self) -> bool {
677708
false // no assignments in scope by default
678709
}
679-
680-
#[inline]
681-
fn join(&self, succ: uint, pred: uint) -> uint {
682-
succ | pred // moves from both preds are in scope
683-
}
684710
}

0 commit comments

Comments
 (0)