@@ -73,6 +73,7 @@ struct GatherLoanCtxt {
73
73
}
74
74
75
75
pub fn gather_loans ( bccx : @BorrowckCtxt ,
76
+ decl : & ast:: fn_decl ,
76
77
body : & ast:: blk )
77
78
-> ( id_range , @mut ~[ Loan ] , @mut move_data:: MoveData ) {
78
79
let glcx = @mut GatherLoanCtxt {
@@ -83,6 +84,7 @@ pub fn gather_loans(bccx: @BorrowckCtxt,
83
84
repeating_ids : ~[ body. node . id ] ,
84
85
move_data : @mut MoveData :: new ( )
85
86
} ;
87
+ glcx. gather_fn_arg_patterns ( decl, body) ;
86
88
let v = visit:: mk_vt ( @visit:: Visitor { visit_expr : gather_loans_in_expr,
87
89
visit_block : gather_loans_in_block,
88
90
visit_fn : gather_loans_in_fn,
@@ -124,6 +126,7 @@ fn gather_loans_in_fn(fk: &visit::fn_kind,
124
126
this. push_repeating_id ( body. node . id ) ;
125
127
visit:: visit_fn ( fk, decl, body, sp, id, ( this, v) ) ;
126
128
this. pop_repeating_id ( body. node . id ) ;
129
+ this. gather_fn_arg_patterns ( decl, body) ;
127
130
}
128
131
}
129
132
}
@@ -138,26 +141,33 @@ fn gather_loans_in_block(blk: &ast::blk,
138
141
fn gather_loans_in_local( local : @ast:: local ,
139
142
( this, vt) : ( @mut GatherLoanCtxt ,
140
143
visit:: vt < @mut GatherLoanCtxt > ) ) {
141
- if local. node . init . is_none ( ) {
142
- // Variable declarations without initializers are considered "moves":
143
- let tcx = this. bccx . tcx ;
144
- do pat_util:: pat_bindings ( tcx. def_map , local. node . pat ) |_, id, span, _| {
145
- gather_moves:: gather_decl ( this. bccx ,
146
- this. move_data ,
147
- id,
148
- span,
149
- id) ;
144
+ match local. node . init {
145
+ None => {
146
+ // Variable declarations without initializers are considered "moves":
147
+ let tcx = this. bccx . tcx ;
148
+ do pat_util:: pat_bindings ( tcx. def_map , local. node . pat )
149
+ |_, id, span, _| {
150
+ gather_moves:: gather_decl( this. bccx,
151
+ this. move_data,
152
+ id,
153
+ span,
154
+ id) ;
155
+ }
150
156
}
151
- } else {
152
- // Variable declarations with initializers are considered "assigns":
153
- let tcx = this. bccx . tcx ;
154
- do pat_util:: pat_bindings ( tcx. def_map , local. node . pat ) |_, id, span, _| {
155
- gather_moves:: gather_assignment ( this. bccx ,
156
- this. move_data ,
157
- id,
158
- span,
159
- @LpVar ( id) ,
160
- id) ;
157
+ Some ( init) => {
158
+ // Variable declarations with initializers are considered "assigns":
159
+ let tcx = this. bccx . tcx ;
160
+ do pat_util:: pat_bindings ( tcx. def_map , local. node . pat )
161
+ |_, id, span, _| {
162
+ gather_moves:: gather_assignment( this. bccx,
163
+ this. move_data,
164
+ id,
165
+ span,
166
+ @LpVar ( id) ,
167
+ id) ;
168
+ }
169
+ let init_cmt = this. bccx. cat_expr( init) ;
170
+ this. gather_pat( init_cmt, local. node. pat, None ) ;
161
171
}
162
172
}
163
173
@@ -230,7 +240,7 @@ fn gather_loans_in_expr(ex: @ast::expr,
230
240
let cmt = this. bccx. cat_expr( ex_v) ;
231
241
for arms. iter( ) . advance |arm| {
232
242
for arm. pats. iter( ) . advance |pat| {
233
- this. gather_pat( cmt, * pat, arm. body. node. id, ex. id) ;
243
+ this. gather_pat( cmt, * pat, Some ( ( arm. body. node. id, ex. id) ) ) ;
234
244
}
235
245
}
236
246
visit:: visit_expr( ex, ( this, vt) ) ;
@@ -596,11 +606,40 @@ impl GatherLoanCtxt {
596
606
}
597
607
}
598
608
599
- pub fn gather_pat ( & mut self ,
600
- discr_cmt : mc:: cmt ,
601
- root_pat : @ast:: pat ,
602
- arm_body_id : ast:: node_id ,
603
- match_id : ast:: node_id ) {
609
+ fn gather_fn_arg_patterns ( & mut self ,
610
+ decl : & ast:: fn_decl ,
611
+ body : & ast:: blk ) {
612
+ /*!
613
+ * Walks the patterns for fn arguments, checking that they
614
+ * do not attempt illegal moves or create refs that outlive
615
+ * the arguments themselves. Just a shallow wrapper around
616
+ * `gather_pat()`.
617
+ */
618
+
619
+ let mc_ctxt = self . bccx . mc_ctxt ( ) ;
620
+ for decl. inputs. each |arg| {
621
+ let arg_ty = ty:: node_id_to_type ( self . tcx ( ) , arg. pat . id ) ;
622
+
623
+ let arg_cmt = mc_ctxt. cat_rvalue (
624
+ arg. id ,
625
+ arg. pat . span ,
626
+ body. node . id , // Arguments live only as long as the fn body.
627
+ arg_ty) ;
628
+
629
+ self . gather_pat ( arg_cmt, arg. pat , None ) ;
630
+ }
631
+ }
632
+
633
+ fn gather_pat ( & mut self ,
634
+ discr_cmt : mc:: cmt ,
635
+ root_pat : @ast:: pat ,
636
+ arm_match_ids : Option < ( ast:: node_id , ast:: node_id ) > ) {
637
+ /*!
638
+ * Walks patterns, examining the bindings to determine if they
639
+ * cause borrows (`ref` bindings, vector patterns) or
640
+ * moves (non-`ref` bindings with linear type).
641
+ */
642
+
604
643
do self . bccx . cat_pattern ( discr_cmt, root_pat) |cmt, pat| {
605
644
match pat. node {
606
645
ast:: pat_ident( bm, _, _) if self . pat_is_binding ( pat) => {
@@ -621,15 +660,19 @@ impl GatherLoanCtxt {
621
660
// with a cat_discr() node. There is a detailed
622
661
// discussion of the function of this node in
623
662
// `lifetime.rs`:
624
- let arm_scope = ty:: re_scope ( arm_body_id) ;
625
- if self . bccx . is_subregion_of ( scope_r, arm_scope) {
626
- let cmt_discr = self . bccx . cat_discr ( cmt, match_id) ;
627
- self . guarantee_valid ( pat. id , pat. span ,
628
- cmt_discr, mutbl, scope_r) ;
629
- } else {
630
- self . guarantee_valid ( pat. id , pat. span ,
631
- cmt, mutbl, scope_r) ;
632
- }
663
+ let cmt_discr = match arm_match_ids {
664
+ None => cmt,
665
+ Some ( ( arm_id, match_id) ) => {
666
+ let arm_scope = ty:: re_scope ( arm_id) ;
667
+ if self . bccx . is_subregion_of ( scope_r, arm_scope) {
668
+ self . bccx . cat_discr ( cmt, match_id)
669
+ } else {
670
+ cmt
671
+ }
672
+ }
673
+ } ;
674
+ self . guarantee_valid ( pat. id , pat. span ,
675
+ cmt_discr, mutbl, scope_r) ;
633
676
}
634
677
ast:: bind_infer => {
635
678
// No borrows here, but there may be moves
@@ -652,6 +695,24 @@ impl GatherLoanCtxt {
652
695
self . vec_slice_info ( slice_pat, slice_ty) ;
653
696
let mcx = self . bccx . mc_ctxt ( ) ;
654
697
let cmt_index = mcx. cat_index ( slice_pat, cmt, 0 ) ;
698
+
699
+ // Note: We declare here that the borrow occurs upon
700
+ // entering the `[...]` pattern. This implies that
701
+ // something like `[a, ..b]` where `a` is a move is
702
+ // illegal, because the borrow is already in effect.
703
+ // In fact such a move would be safe-ish, but it
704
+ // effectively *requires* that we use the nulling
705
+ // out semantics to indicate when a value has been
706
+ // moved, which we are trying to move away from.
707
+ // Otherwise, how can we indicate that the first
708
+ // element in the vector has been moved?
709
+ // Eventually, we could perhaps modify this rule to
710
+ // permit `[..a, b]` where `b` is a move, because in
711
+ // that case we can adjust the length of the
712
+ // original vec accordingly, but we'd have to make
713
+ // trans do the right thing, and it would only work
714
+ // for `~` vectors. It seems simpler to just require
715
+ // that people call `vec.pop()` or `vec.unshift()`.
655
716
self . guarantee_valid ( pat. id , pat. span ,
656
717
cmt_index, slice_mutbl, slice_r) ;
657
718
}
0 commit comments