]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012 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 | //! This module implements the check that the lifetime of a borrow | |
12 | //! does not exceed the lifetime of the value being borrowed. | |
13 | ||
14 | use borrowck::*; | |
15 | use rustc::middle::expr_use_visitor as euv; | |
16 | use rustc::middle::mem_categorization as mc; | |
17 | use rustc::middle::region; | |
18 | use rustc::middle::ty; | |
62682a34 | 19 | |
1a4d82fc JJ |
20 | use syntax::ast; |
21 | use syntax::codemap::Span; | |
22 | ||
23 | type R = Result<(),()>; | |
24 | ||
25 | pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, | |
26 | item_scope: region::CodeExtent, | |
27 | span: Span, | |
28 | cause: euv::LoanCause, | |
29 | cmt: mc::cmt<'tcx>, | |
30 | loan_region: ty::Region, | |
31 | _: ty::BorrowKind) | |
32 | -> Result<(),()> { | |
33 | //! Reports error if `loan_region` is larger than S | |
34 | //! where S is `item_scope` if `cmt` is an upvar, | |
35 | //! and is scope of `cmt` otherwise. | |
62682a34 SL |
36 | debug!("guarantee_lifetime(cmt={:?}, loan_region={:?})", |
37 | cmt, loan_region); | |
1a4d82fc JJ |
38 | let ctxt = GuaranteeLifetimeContext {bccx: bccx, |
39 | item_scope: item_scope, | |
40 | span: span, | |
41 | cause: cause, | |
42 | loan_region: loan_region, | |
43 | cmt_original: cmt.clone()}; | |
44 | ctxt.check(&cmt, None) | |
45 | } | |
46 | ||
47 | /////////////////////////////////////////////////////////////////////////// | |
48 | // Private | |
49 | ||
50 | struct GuaranteeLifetimeContext<'a, 'tcx: 'a> { | |
51 | bccx: &'a BorrowckCtxt<'a, 'tcx>, | |
52 | ||
53 | // the scope of the function body for the enclosing item | |
54 | item_scope: region::CodeExtent, | |
55 | ||
56 | span: Span, | |
57 | cause: euv::LoanCause, | |
58 | loan_region: ty::Region, | |
59 | cmt_original: mc::cmt<'tcx> | |
60 | } | |
61 | ||
62 | impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { | |
63 | ||
64 | fn check(&self, cmt: &mc::cmt<'tcx>, discr_scope: Option<ast::NodeId>) -> R { | |
65 | //! Main routine. Walks down `cmt` until we find the | |
66 | //! "guarantor". Reports an error if `self.loan_region` is | |
67 | //! larger than scope of `cmt`. | |
62682a34 SL |
68 | debug!("guarantee_lifetime.check(cmt={:?}, loan_region={:?})", |
69 | cmt, | |
70 | self.loan_region); | |
1a4d82fc JJ |
71 | |
72 | match cmt.cat { | |
73 | mc::cat_rvalue(..) | | |
74 | mc::cat_local(..) | // L-Local | |
75 | mc::cat_upvar(..) | | |
76 | mc::cat_deref(_, _, mc::BorrowedPtr(..)) | // L-Deref-Borrowed | |
77 | mc::cat_deref(_, _, mc::Implicit(..)) | | |
78 | mc::cat_deref(_, _, mc::UnsafePtr(..)) => { | |
79 | self.check_scope(self.scope(cmt)) | |
80 | } | |
81 | ||
82 | mc::cat_static_item => { | |
83 | Ok(()) | |
84 | } | |
85 | ||
86 | mc::cat_downcast(ref base, _) | | |
87 | mc::cat_deref(ref base, _, mc::Unique) | // L-Deref-Send | |
88 | mc::cat_interior(ref base, _) => { // L-Field | |
89 | self.check(base, discr_scope) | |
90 | } | |
91 | } | |
92 | } | |
93 | ||
94 | fn check_scope(&self, max_scope: ty::Region) -> R { | |
95 | //! Reports an error if `loan_region` is larger than `max_scope` | |
96 | ||
97 | if !self.bccx.is_subregion_of(self.loan_region, max_scope) { | |
98 | Err(self.report_error(err_out_of_scope(max_scope, self.loan_region))) | |
99 | } else { | |
100 | Ok(()) | |
101 | } | |
102 | } | |
103 | ||
104 | fn scope(&self, cmt: &mc::cmt) -> ty::Region { | |
105 | //! Returns the maximal region scope for the which the | |
106 | //! lvalue `cmt` is guaranteed to be valid without any | |
107 | //! rooting etc, and presuming `cmt` is not mutated. | |
108 | ||
1a4d82fc JJ |
109 | match cmt.cat { |
110 | mc::cat_rvalue(temp_scope) => { | |
111 | temp_scope | |
112 | } | |
113 | mc::cat_upvar(..) => { | |
114 | ty::ReScope(self.item_scope) | |
115 | } | |
116 | mc::cat_static_item => { | |
117 | ty::ReStatic | |
118 | } | |
119 | mc::cat_local(local_id) => { | |
120 | ty::ReScope(self.bccx.tcx.region_maps.var_scope(local_id)) | |
121 | } | |
122 | mc::cat_deref(_, _, mc::UnsafePtr(..)) => { | |
123 | ty::ReStatic | |
124 | } | |
125 | mc::cat_deref(_, _, mc::BorrowedPtr(_, r)) | | |
126 | mc::cat_deref(_, _, mc::Implicit(_, r)) => { | |
127 | r | |
128 | } | |
129 | mc::cat_downcast(ref cmt, _) | | |
130 | mc::cat_deref(ref cmt, _, mc::Unique) | | |
131 | mc::cat_interior(ref cmt, _) => { | |
132 | self.scope(cmt) | |
133 | } | |
134 | } | |
135 | } | |
136 | ||
137 | fn report_error(&self, code: bckerr_code) { | |
138 | self.bccx.report(BckError { cmt: self.cmt_original.clone(), | |
139 | span: self.span, | |
c1a9b12d | 140 | cause: BorrowViolation(self.cause), |
1a4d82fc JJ |
141 | code: code }); |
142 | } | |
143 | } |