]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | // ---------------------------------------------------------------------- | |
12 | // Gathering loans | |
13 | // | |
14 | // The borrow check proceeds in two phases. In phase one, we gather the full | |
15 | // set of loans that are required at any point. These are sorted according to | |
16 | // their associated scopes. In phase two, checking loans, we will then make | |
17 | // sure that all of these loans are honored. | |
18 | ||
19 | use borrowck::*; | |
20 | use borrowck::move_data::MoveData; | |
21 | use rustc::middle::expr_use_visitor as euv; | |
22 | use rustc::middle::mem_categorization as mc; | |
92a42be0 | 23 | use rustc::middle::mem_categorization::Categorization; |
1a4d82fc | 24 | use rustc::middle::region; |
54a0048b | 25 | use rustc::ty::{self, TyCtxt}; |
62682a34 | 26 | |
1a4d82fc | 27 | use syntax::ast; |
3157f602 | 28 | use syntax_pos::Span; |
54a0048b | 29 | use rustc::hir; |
1a4d82fc | 30 | |
9cc50fc6 SL |
31 | use self::restrictions::RestrictionResult; |
32 | ||
1a4d82fc JJ |
33 | mod lifetime; |
34 | mod restrictions; | |
35 | mod gather_moves; | |
36 | mod move_error; | |
37 | ||
38 | pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, | |
32a655c1 | 39 | body: hir::BodyId) |
7cac9316 XL |
40 | -> (Vec<Loan<'tcx>>, move_data::MoveData<'tcx>) { |
41 | let def_id = bccx.tcx.hir.body_owner_def_id(body); | |
7cac9316 | 42 | let param_env = bccx.tcx.param_env(def_id); |
1a4d82fc | 43 | let mut glcx = GatherLoanCtxt { |
3b2f2976 | 44 | bccx, |
1a4d82fc | 45 | all_loans: Vec::new(), |
ea8adc8c XL |
46 | item_ub: region::Scope::Node(bccx.tcx.hir.body(body).value.hir_id.local_id), |
47 | move_data: MoveData::default(), | |
1a4d82fc JJ |
48 | move_error_collector: move_error::MoveErrorCollector::new(), |
49 | }; | |
50 | ||
abe05a73 XL |
51 | let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id); |
52 | euv::ExprUseVisitor::new(&mut glcx, | |
53 | bccx.tcx, | |
54 | param_env, | |
55 | &bccx.region_scope_tree, | |
56 | bccx.tables, | |
57 | Some(rvalue_promotable_map)) | |
ea8adc8c | 58 | .consume_body(bccx.body); |
1a4d82fc JJ |
59 | |
60 | glcx.report_potential_errors(); | |
61 | let GatherLoanCtxt { all_loans, move_data, .. } = glcx; | |
62 | (all_loans, move_data) | |
63 | } | |
64 | ||
65 | struct GatherLoanCtxt<'a, 'tcx: 'a> { | |
66 | bccx: &'a BorrowckCtxt<'a, 'tcx>, | |
67 | move_data: move_data::MoveData<'tcx>, | |
68 | move_error_collector: move_error::MoveErrorCollector<'tcx>, | |
69 | all_loans: Vec<Loan<'tcx>>, | |
70 | /// `item_ub` is used as an upper-bound on the lifetime whenever we | |
71 | /// ask for the scope of an expression categorized as an upvar. | |
ea8adc8c | 72 | item_ub: region::Scope, |
1a4d82fc JJ |
73 | } |
74 | ||
75 | impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { | |
76 | fn consume(&mut self, | |
77 | consume_id: ast::NodeId, | |
78 | _consume_span: Span, | |
79 | cmt: mc::cmt<'tcx>, | |
80 | mode: euv::ConsumeMode) { | |
62682a34 SL |
81 | debug!("consume(consume_id={}, cmt={:?}, mode={:?})", |
82 | consume_id, cmt, mode); | |
1a4d82fc JJ |
83 | |
84 | match mode { | |
85 | euv::Move(move_reason) => { | |
86 | gather_moves::gather_move_from_expr( | |
92a42be0 | 87 | self.bccx, &self.move_data, &mut self.move_error_collector, |
ea8adc8c | 88 | self.bccx.tcx.hir.node_to_hir_id(consume_id).local_id, cmt, move_reason); |
1a4d82fc JJ |
89 | } |
90 | euv::Copy => { } | |
91 | } | |
92 | } | |
93 | ||
94 | fn matched_pat(&mut self, | |
e9174d1e | 95 | matched_pat: &hir::Pat, |
1a4d82fc JJ |
96 | cmt: mc::cmt<'tcx>, |
97 | mode: euv::MatchMode) { | |
62682a34 SL |
98 | debug!("matched_pat(matched_pat={:?}, cmt={:?}, mode={:?})", |
99 | matched_pat, | |
100 | cmt, | |
1a4d82fc | 101 | mode); |
1a4d82fc JJ |
102 | } |
103 | ||
104 | fn consume_pat(&mut self, | |
e9174d1e | 105 | consume_pat: &hir::Pat, |
1a4d82fc JJ |
106 | cmt: mc::cmt<'tcx>, |
107 | mode: euv::ConsumeMode) { | |
62682a34 SL |
108 | debug!("consume_pat(consume_pat={:?}, cmt={:?}, mode={:?})", |
109 | consume_pat, | |
110 | cmt, | |
1a4d82fc JJ |
111 | mode); |
112 | ||
113 | match mode { | |
114 | euv::Copy => { return; } | |
115 | euv::Move(_) => { } | |
116 | } | |
117 | ||
118 | gather_moves::gather_move_from_pat( | |
92a42be0 | 119 | self.bccx, &self.move_data, &mut self.move_error_collector, |
1a4d82fc JJ |
120 | consume_pat, cmt); |
121 | } | |
122 | ||
123 | fn borrow(&mut self, | |
124 | borrow_id: ast::NodeId, | |
125 | borrow_span: Span, | |
126 | cmt: mc::cmt<'tcx>, | |
7cac9316 | 127 | loan_region: ty::Region<'tcx>, |
1a4d82fc JJ |
128 | bk: ty::BorrowKind, |
129 | loan_cause: euv::LoanCause) | |
130 | { | |
62682a34 | 131 | debug!("borrow(borrow_id={}, cmt={:?}, loan_region={:?}, \ |
1a4d82fc | 132 | bk={:?}, loan_cause={:?})", |
62682a34 | 133 | borrow_id, cmt, loan_region, |
1a4d82fc | 134 | bk, loan_cause); |
ea8adc8c XL |
135 | let hir_id = self.bccx.tcx.hir.node_to_hir_id(borrow_id); |
136 | self.guarantee_valid(hir_id.local_id, | |
1a4d82fc JJ |
137 | borrow_span, |
138 | cmt, | |
139 | bk, | |
140 | loan_region, | |
141 | loan_cause); | |
142 | } | |
143 | ||
144 | fn mutate(&mut self, | |
145 | assignment_id: ast::NodeId, | |
146 | assignment_span: Span, | |
147 | assignee_cmt: mc::cmt<'tcx>, | |
148 | mode: euv::MutateMode) | |
149 | { | |
c1a9b12d SL |
150 | self.guarantee_assignment_valid(assignment_id, |
151 | assignment_span, | |
152 | assignee_cmt, | |
153 | mode); | |
1a4d82fc JJ |
154 | } |
155 | ||
32a655c1 | 156 | fn decl_without_init(&mut self, id: ast::NodeId, _span: Span) { |
3b2f2976 XL |
157 | let ty = self.bccx |
158 | .tables | |
159 | .node_id_to_type(self.bccx.tcx.hir.node_to_hir_id(id)); | |
32a655c1 | 160 | gather_moves::gather_decl(self.bccx, &self.move_data, id, ty); |
1a4d82fc JJ |
161 | } |
162 | } | |
163 | ||
c34b1796 | 164 | /// Implements the A-* rules in README.md. |
1a4d82fc JJ |
165 | fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, |
166 | borrow_span: Span, | |
c1a9b12d | 167 | loan_cause: AliasableViolationKind, |
1a4d82fc JJ |
168 | cmt: mc::cmt<'tcx>, |
169 | req_kind: ty::BorrowKind) | |
170 | -> Result<(),()> { | |
171 | ||
a7813a04 | 172 | let aliasability = cmt.freely_aliasable(); |
c34b1796 AL |
173 | debug!("check_aliasability aliasability={:?} req_kind={:?}", |
174 | aliasability, req_kind); | |
175 | ||
176 | match (aliasability, req_kind) { | |
177 | (mc::Aliasability::NonAliasable, _) => { | |
1a4d82fc JJ |
178 | /* Uniquely accessible path -- OK for `&` and `&mut` */ |
179 | Ok(()) | |
180 | } | |
62682a34 SL |
181 | (mc::Aliasability::FreelyAliasable(mc::AliasableStatic), ty::ImmBorrow) => { |
182 | // Borrow of an immutable static item. | |
183 | Ok(()) | |
1a4d82fc | 184 | } |
62682a34 | 185 | (mc::Aliasability::FreelyAliasable(mc::AliasableStaticMut), _) => { |
1a4d82fc JJ |
186 | // Even touching a static mut is considered unsafe. We assume the |
187 | // user knows what they're doing in these cases. | |
188 | Ok(()) | |
189 | } | |
c34b1796 AL |
190 | (mc::Aliasability::FreelyAliasable(alias_cause), ty::UniqueImmBorrow) | |
191 | (mc::Aliasability::FreelyAliasable(alias_cause), ty::MutBorrow) => { | |
1a4d82fc JJ |
192 | bccx.report_aliasability_violation( |
193 | borrow_span, | |
c1a9b12d | 194 | loan_cause, |
32a655c1 SL |
195 | alias_cause, |
196 | cmt); | |
1a4d82fc JJ |
197 | Err(()) |
198 | } | |
9e0c209e | 199 | (..) => { |
1a4d82fc JJ |
200 | Ok(()) |
201 | } | |
202 | } | |
203 | } | |
204 | ||
c1a9b12d SL |
205 | /// Implements the M-* rules in README.md. |
206 | fn check_mutability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, | |
207 | borrow_span: Span, | |
208 | cause: AliasableViolationKind, | |
209 | cmt: mc::cmt<'tcx>, | |
210 | req_kind: ty::BorrowKind) | |
211 | -> Result<(),()> { | |
212 | debug!("check_mutability(cause={:?} cmt={:?} req_kind={:?}", | |
213 | cause, cmt, req_kind); | |
214 | match req_kind { | |
215 | ty::UniqueImmBorrow | ty::ImmBorrow => { | |
216 | match cmt.mutbl { | |
217 | // I am intentionally leaving this here to help | |
218 | // refactoring if, in the future, we should add new | |
219 | // kinds of mutability. | |
220 | mc::McImmutable | mc::McDeclared | mc::McInherited => { | |
221 | // both imm and mut data can be lent as imm; | |
222 | // for mutable data, this is a freeze | |
223 | Ok(()) | |
224 | } | |
225 | } | |
226 | } | |
227 | ||
228 | ty::MutBorrow => { | |
229 | // Only mutable data can be lent as mutable. | |
230 | if !cmt.mutbl.is_mutable() { | |
231 | Err(bccx.report(BckError { span: borrow_span, | |
3b2f2976 XL |
232 | cause, |
233 | cmt, | |
c1a9b12d SL |
234 | code: err_mutbl })) |
235 | } else { | |
236 | Ok(()) | |
237 | } | |
238 | } | |
239 | } | |
240 | } | |
241 | ||
1a4d82fc | 242 | impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { |
a7813a04 | 243 | pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.bccx.tcx } |
1a4d82fc | 244 | |
c1a9b12d SL |
245 | /// Guarantees that `cmt` is assignable, or reports an error. |
246 | fn guarantee_assignment_valid(&mut self, | |
247 | assignment_id: ast::NodeId, | |
248 | assignment_span: Span, | |
249 | cmt: mc::cmt<'tcx>, | |
250 | mode: euv::MutateMode) { | |
251 | ||
252 | let opt_lp = opt_loan_path(&cmt); | |
253 | debug!("guarantee_assignment_valid(assignment_id={}, cmt={:?}) opt_lp={:?}", | |
254 | assignment_id, cmt, opt_lp); | |
255 | ||
92a42be0 | 256 | if let Categorization::Local(..) = cmt.cat { |
c1a9b12d SL |
257 | // Only re-assignments to locals require it to be |
258 | // mutable - this is checked in check_loans. | |
259 | } else { | |
260 | // Check that we don't allow assignments to non-mutable data. | |
261 | if check_mutability(self.bccx, assignment_span, MutabilityViolation, | |
262 | cmt.clone(), ty::MutBorrow).is_err() { | |
263 | return; // reported an error, no sense in reporting more. | |
264 | } | |
265 | } | |
266 | ||
267 | // Check that we don't allow assignments to aliasable data | |
268 | if check_aliasability(self.bccx, assignment_span, MutabilityViolation, | |
269 | cmt.clone(), ty::MutBorrow).is_err() { | |
270 | return; // reported an error, no sense in reporting more. | |
271 | } | |
272 | ||
273 | match opt_lp { | |
274 | Some(lp) => { | |
92a42be0 | 275 | if let Categorization::Local(..) = cmt.cat { |
c1a9b12d SL |
276 | // Only re-assignments to locals require it to be |
277 | // mutable - this is checked in check_loans. | |
278 | } else { | |
279 | self.mark_loan_path_as_mutated(&lp); | |
280 | } | |
281 | gather_moves::gather_assignment(self.bccx, &self.move_data, | |
ea8adc8c XL |
282 | self.bccx.tcx.hir.node_to_hir_id(assignment_id) |
283 | .local_id, | |
284 | assignment_span, | |
285 | lp, | |
286 | self.bccx.tcx.hir.node_to_hir_id(cmt.id).local_id, | |
287 | mode); | |
c1a9b12d SL |
288 | } |
289 | None => { | |
290 | // This can occur with e.g. `*foo() = 5`. In such | |
291 | // cases, there is no need to check for conflicts | |
292 | // with moves etc, just ignore. | |
293 | } | |
294 | } | |
295 | } | |
296 | ||
1a4d82fc JJ |
297 | /// Guarantees that `addr_of(cmt)` will be valid for the duration of `static_scope_r`, or |
298 | /// reports an error. This may entail taking out loans, which will be added to the | |
299 | /// `req_loan_map`. | |
300 | fn guarantee_valid(&mut self, | |
ea8adc8c | 301 | borrow_id: hir::ItemLocalId, |
1a4d82fc JJ |
302 | borrow_span: Span, |
303 | cmt: mc::cmt<'tcx>, | |
304 | req_kind: ty::BorrowKind, | |
7cac9316 | 305 | loan_region: ty::Region<'tcx>, |
1a4d82fc | 306 | cause: euv::LoanCause) { |
ea8adc8c | 307 | debug!("guarantee_valid(borrow_id={:?}, cmt={:?}, \ |
1a4d82fc JJ |
308 | req_mutbl={:?}, loan_region={:?})", |
309 | borrow_id, | |
62682a34 | 310 | cmt, |
1a4d82fc JJ |
311 | req_kind, |
312 | loan_region); | |
313 | ||
314 | // a loan for the empty region can never be dereferenced, so | |
315 | // it is always safe | |
9e0c209e | 316 | if *loan_region == ty::ReEmpty { |
1a4d82fc JJ |
317 | return; |
318 | } | |
319 | ||
320 | // Check that the lifetime of the borrow does not exceed | |
321 | // the lifetime of the data being borrowed. | |
322 | if lifetime::guarantee_lifetime(self.bccx, self.item_ub, | |
323 | borrow_span, cause, cmt.clone(), loan_region, | |
324 | req_kind).is_err() { | |
325 | return; // reported an error, no sense in reporting more. | |
326 | } | |
327 | ||
328 | // Check that we don't allow mutable borrows of non-mutable data. | |
c1a9b12d | 329 | if check_mutability(self.bccx, borrow_span, BorrowViolation(cause), |
1a4d82fc JJ |
330 | cmt.clone(), req_kind).is_err() { |
331 | return; // reported an error, no sense in reporting more. | |
332 | } | |
333 | ||
334 | // Check that we don't allow mutable borrows of aliasable data. | |
c1a9b12d | 335 | if check_aliasability(self.bccx, borrow_span, BorrowViolation(cause), |
1a4d82fc JJ |
336 | cmt.clone(), req_kind).is_err() { |
337 | return; // reported an error, no sense in reporting more. | |
338 | } | |
339 | ||
340 | // Compute the restrictions that are required to enforce the | |
341 | // loan is safe. | |
342 | let restr = restrictions::compute_restrictions( | |
343 | self.bccx, borrow_span, cause, | |
344 | cmt.clone(), loan_region); | |
345 | ||
346 | debug!("guarantee_valid(): restrictions={:?}", restr); | |
347 | ||
348 | // Create the loan record (if needed). | |
349 | let loan = match restr { | |
9cc50fc6 | 350 | RestrictionResult::Safe => { |
1a4d82fc JJ |
351 | // No restrictions---no loan record necessary |
352 | return; | |
353 | } | |
354 | ||
9cc50fc6 | 355 | RestrictionResult::SafeIf(loan_path, restricted_paths) => { |
9e0c209e | 356 | let loan_scope = match *loan_region { |
1a4d82fc JJ |
357 | ty::ReScope(scope) => scope, |
358 | ||
7cac9316 | 359 | ty::ReEarlyBound(ref br) => { |
ea8adc8c | 360 | self.bccx.region_scope_tree.early_free_scope(self.tcx(), br) |
7cac9316 XL |
361 | } |
362 | ||
363 | ty::ReFree(ref fr) => { | |
ea8adc8c | 364 | self.bccx.region_scope_tree.free_scope(self.tcx(), fr) |
7cac9316 | 365 | } |
e9174d1e SL |
366 | |
367 | ty::ReStatic => self.item_ub, | |
1a4d82fc JJ |
368 | |
369 | ty::ReEmpty | | |
370 | ty::ReLateBound(..) | | |
e9174d1e | 371 | ty::ReVar(..) | |
3157f602 XL |
372 | ty::ReSkolemized(..) | |
373 | ty::ReErased => { | |
54a0048b | 374 | span_bug!( |
1a4d82fc | 375 | cmt.span, |
54a0048b SL |
376 | "invalid borrow lifetime: {:?}", |
377 | loan_region); | |
1a4d82fc JJ |
378 | } |
379 | }; | |
380 | debug!("loan_scope = {:?}", loan_scope); | |
381 | ||
ea8adc8c | 382 | let borrow_scope = region::Scope::Node(borrow_id); |
1a4d82fc JJ |
383 | let gen_scope = self.compute_gen_scope(borrow_scope, loan_scope); |
384 | debug!("gen_scope = {:?}", gen_scope); | |
385 | ||
7453a54e | 386 | let kill_scope = self.compute_kill_scope(loan_scope, &loan_path); |
1a4d82fc JJ |
387 | debug!("kill_scope = {:?}", kill_scope); |
388 | ||
389 | if req_kind == ty::MutBorrow { | |
7453a54e | 390 | self.mark_loan_path_as_mutated(&loan_path); |
1a4d82fc JJ |
391 | } |
392 | ||
393 | Loan { | |
394 | index: self.all_loans.len(), | |
3b2f2976 | 395 | loan_path, |
1a4d82fc | 396 | kind: req_kind, |
3b2f2976 XL |
397 | gen_scope, |
398 | kill_scope, | |
1a4d82fc | 399 | span: borrow_span, |
3b2f2976 XL |
400 | restricted_paths, |
401 | cause, | |
1a4d82fc JJ |
402 | } |
403 | } | |
404 | }; | |
405 | ||
ea8adc8c | 406 | debug!("guarantee_valid(borrow_id={:?}), loan={:?}", |
62682a34 | 407 | borrow_id, loan); |
1a4d82fc JJ |
408 | |
409 | // let loan_path = loan.loan_path; | |
410 | // let loan_gen_scope = loan.gen_scope; | |
411 | // let loan_kill_scope = loan.kill_scope; | |
412 | self.all_loans.push(loan); | |
413 | ||
414 | // if loan_gen_scope != borrow_id { | |
abe05a73 | 415 | // FIXME(https://github.com/rust-lang/rfcs/issues/811) Nested method calls |
1a4d82fc JJ |
416 | // |
417 | // Typically, the scope of the loan includes the point at | |
418 | // which the loan is originated. This | |
419 | // This is a subtle case. See the test case | |
420 | // <compile-fail/borrowck-bad-nested-calls-free.rs> | |
421 | // to see what we are guarding against. | |
422 | ||
423 | //let restr = restrictions::compute_restrictions( | |
424 | // self.bccx, borrow_span, cmt, RESTR_EMPTY); | |
425 | //let loan = { | |
1a4d82fc | 426 | // Loan { |
abe05a73 | 427 | // index: self.all_loans.len(), |
3b2f2976 XL |
428 | // loan_path, |
429 | // cmt, | |
1a4d82fc JJ |
430 | // mutbl: ConstMutability, |
431 | // gen_scope: borrow_id, | |
3b2f2976 | 432 | // kill_scope, |
1a4d82fc | 433 | // span: borrow_span, |
3b2f2976 | 434 | // restrictions, |
1a4d82fc JJ |
435 | // } |
436 | // } | |
1a4d82fc JJ |
437 | } |
438 | ||
439 | pub fn mark_loan_path_as_mutated(&self, loan_path: &LoanPath) { | |
440 | //! For mutable loans of content whose mutability derives | |
441 | //! from a local variable, mark the mutability decl as necessary. | |
442 | ||
3b2f2976 XL |
443 | let mut wrapped_path = Some(loan_path); |
444 | let mut through_borrow = false; | |
445 | ||
446 | while let Some(current_path) = wrapped_path { | |
447 | wrapped_path = match current_path.kind { | |
448 | LpVar(local_id) => { | |
449 | if !through_borrow { | |
abe05a73 XL |
450 | let hir_id = self.bccx.tcx.hir.node_to_hir_id(local_id); |
451 | self.bccx.used_mut_nodes.borrow_mut().insert(hir_id); | |
3b2f2976 XL |
452 | } |
453 | None | |
454 | } | |
455 | LpUpvar(ty::UpvarId{ var_id, closure_expr_id: _ }) => { | |
abe05a73 | 456 | self.bccx.used_mut_nodes.borrow_mut().insert(var_id); |
3b2f2976 XL |
457 | None |
458 | } | |
459 | LpExtend(ref base, mc::McInherited, LpDeref(pointer_kind)) | | |
460 | LpExtend(ref base, mc::McDeclared, LpDeref(pointer_kind)) => { | |
461 | if pointer_kind != mc::Unique { | |
462 | through_borrow = true; | |
463 | } | |
464 | Some(base) | |
465 | } | |
466 | LpDowncast(ref base, _) | | |
467 | LpExtend(ref base, mc::McInherited, _) | | |
468 | LpExtend(ref base, mc::McDeclared, _) => { | |
469 | Some(base) | |
470 | } | |
471 | LpExtend(_, mc::McImmutable, _) => { | |
472 | // Nothing to do. | |
473 | None | |
474 | } | |
1a4d82fc JJ |
475 | } |
476 | } | |
3b2f2976 | 477 | |
1a4d82fc JJ |
478 | } |
479 | ||
480 | pub fn compute_gen_scope(&self, | |
ea8adc8c XL |
481 | borrow_scope: region::Scope, |
482 | loan_scope: region::Scope) | |
483 | -> region::Scope { | |
1a4d82fc JJ |
484 | //! Determine when to introduce the loan. Typically the loan |
485 | //! is introduced at the point of the borrow, but in some cases, | |
486 | //! notably method arguments, the loan may be introduced only | |
487 | //! later, once it comes into scope. | |
488 | ||
ea8adc8c | 489 | if self.bccx.region_scope_tree.is_subscope_of(borrow_scope, loan_scope) { |
1a4d82fc JJ |
490 | borrow_scope |
491 | } else { | |
492 | loan_scope | |
493 | } | |
494 | } | |
495 | ||
ea8adc8c XL |
496 | pub fn compute_kill_scope(&self, loan_scope: region::Scope, lp: &LoanPath<'tcx>) |
497 | -> region::Scope { | |
1a4d82fc JJ |
498 | //! Determine when the loan restrictions go out of scope. |
499 | //! This is either when the lifetime expires or when the | |
500 | //! local variable which roots the loan-path goes out of scope, | |
501 | //! whichever happens faster. | |
502 | //! | |
503 | //! It may seem surprising that we might have a loan region | |
504 | //! larger than the variable which roots the loan-path; this can | |
505 | //! come about when variables of `&mut` type are re-borrowed, | |
506 | //! as in this example: | |
507 | //! | |
92a42be0 SL |
508 | //! struct Foo { counter: u32 } |
509 | //! | |
510 | //! fn counter<'a>(v: &'a mut Foo) -> &'a mut u32 { | |
1a4d82fc JJ |
511 | //! &mut v.counter |
512 | //! } | |
513 | //! | |
514 | //! In this case, the reference (`'a`) outlives the | |
515 | //! variable `v` that hosts it. Note that this doesn't come up | |
516 | //! with immutable `&` pointers, because borrows of such pointers | |
517 | //! do not require restrictions and hence do not cause a loan. | |
518 | ||
7cac9316 | 519 | let lexical_scope = lp.kill_scope(self.bccx); |
ea8adc8c | 520 | if self.bccx.region_scope_tree.is_subscope_of(lexical_scope, loan_scope) { |
1a4d82fc JJ |
521 | lexical_scope |
522 | } else { | |
ea8adc8c | 523 | assert!(self.bccx.region_scope_tree.is_subscope_of(loan_scope, lexical_scope)); |
1a4d82fc JJ |
524 | loan_scope |
525 | } | |
526 | } | |
527 | ||
528 | pub fn report_potential_errors(&self) { | |
529 | self.move_error_collector.report_potential_errors(self.bccx); | |
530 | } | |
531 | } |