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