12
12
13
13
#![ allow( non_camel_case_types) ]
14
14
15
+ use middle:: cfg;
15
16
use middle:: dataflow:: DataFlowContext ;
17
+ use middle:: dataflow:: BitwiseOperator ;
16
18
use middle:: dataflow:: DataFlowOperator ;
17
19
use middle:: def;
18
20
use euv = middle:: expr_use_visitor;
@@ -126,20 +128,28 @@ fn borrowck_fn(this: &mut BorrowckCtxt,
126
128
let id_range = ast_util:: compute_id_range_for_fn_body ( fk, decl, body, sp, id) ;
127
129
let ( all_loans, move_data) =
128
130
gather_loans:: gather_loans_in_fn ( this, decl, body) ;
131
+ let cfg = cfg:: CFG :: new ( this. tcx , body) ;
132
+
129
133
let mut loan_dfcx =
130
134
DataFlowContext :: new ( this. tcx ,
135
+ "borrowck" ,
136
+ Some ( decl) ,
137
+ & cfg,
131
138
LoanDataFlowOperator ,
132
139
id_range,
133
140
all_loans. len ( ) ) ;
134
141
for ( loan_idx, loan) in all_loans. iter ( ) . enumerate ( ) {
135
142
loan_dfcx. add_gen ( loan. gen_scope , loan_idx) ;
136
143
loan_dfcx. add_kill ( loan. kill_scope , loan_idx) ;
137
144
}
138
- loan_dfcx. propagate ( body) ;
145
+ loan_dfcx. add_kills_from_flow_exits ( & cfg) ;
146
+ loan_dfcx. propagate ( & cfg, body) ;
139
147
140
148
let flowed_moves = move_data:: FlowedMoveData :: new ( move_data,
141
149
this. tcx ,
150
+ & cfg,
142
151
id_range,
152
+ decl,
143
153
body) ;
144
154
145
155
check_loans:: check_loans ( this, & loan_dfcx, flowed_moves,
@@ -191,6 +201,7 @@ pub struct Loan {
191
201
#[ deriving( PartialEq , Eq , Hash ) ]
192
202
pub enum LoanPath {
193
203
LpVar ( ast:: NodeId ) , // `x` in doc.rs
204
+ LpUpvar ( ty:: UpvarId ) , // `x` captured by-value into closure
194
205
LpExtend ( Rc < LoanPath > , mc:: MutabilityCategory , LoanPathElem )
195
206
}
196
207
@@ -200,11 +211,25 @@ pub enum LoanPathElem {
200
211
LpInterior ( mc:: InteriorKind ) // `LV.f` in doc.rs
201
212
}
202
213
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
+
203
226
impl LoanPath {
204
- pub fn node_id ( & self ) -> ast:: NodeId {
227
+ pub fn kill_scope ( & self , tcx : & ty :: ctxt ) -> ast:: NodeId {
205
228
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) ,
208
233
}
209
234
}
210
235
}
@@ -224,12 +249,18 @@ pub fn opt_loan_path(cmt: &mc::cmt) -> Option<Rc<LoanPath>> {
224
249
}
225
250
226
251
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) => {
230
253
Some ( Rc :: new ( LpVar ( id) ) )
231
254
}
232
255
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
+
233
264
mc:: cat_deref( ref cmt_base, _, pk) => {
234
265
opt_loan_path ( cmt_base) . map ( |lp| {
235
266
Rc :: new ( LpExtend ( lp, cmt. mutbl , LpDeref ( pk) ) )
@@ -683,6 +714,7 @@ impl<'a> BorrowckCtxt<'a> {
683
714
loan_path : & LoanPath ,
684
715
out : & mut String ) {
685
716
match * loan_path {
717
+ LpUpvar ( ty:: UpvarId { var_id : id, closure_expr_id : _ } ) |
686
718
LpVar ( id) => {
687
719
out. push_str ( ty:: local_var_name_str ( self . tcx , id) . get ( ) ) ;
688
720
}
@@ -724,7 +756,7 @@ impl<'a> BorrowckCtxt<'a> {
724
756
self . append_autoderefd_loan_path_to_str ( & * * lp_base, out)
725
757
}
726
758
727
- LpVar ( ..) | LpExtend ( _, _, LpInterior ( ..) ) => {
759
+ LpVar ( ..) | LpUpvar ( .. ) | LpExtend ( _, _, LpInterior ( ..) ) => {
728
760
self . append_loan_path_to_str ( loan_path, out)
729
761
}
730
762
}
@@ -753,15 +785,17 @@ fn is_statement_scope(tcx: &ty::ctxt, region: ty::Region) -> bool {
753
785
}
754
786
}
755
787
756
- impl DataFlowOperator for LoanDataFlowOperator {
788
+ impl BitwiseOperator for LoanDataFlowOperator {
757
789
#[ 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
760
792
}
793
+ }
761
794
795
+ impl DataFlowOperator for LoanDataFlowOperator {
762
796
#[ 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
765
799
}
766
800
}
767
801
@@ -784,6 +818,12 @@ impl Repr for LoanPath {
784
818
( format ! ( "$({})" , tcx. map. node_to_str( id) ) ) . to_string ( )
785
819
}
786
820
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
+
787
827
& LpExtend ( ref lp, _, LpDeref ( _) ) => {
788
828
( format ! ( "{}.*" , lp. repr( tcx) ) ) . to_string ( )
789
829
}
0 commit comments