1212
1313#![ allow( non_camel_case_types) ]
1414
15+ use middle:: cfg;
1516use middle:: dataflow:: DataFlowContext ;
17+ use middle:: dataflow:: BitwiseOperator ;
1618use middle:: dataflow:: DataFlowOperator ;
1719use middle:: def;
1820use 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 ) ]
192202pub 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+
203226impl 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 }
0 commit comments