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 /*!
12 * Computes the restrictions that result from a borrow.
13 */
14
15 use middle::borrowck::*;
16 use euv = middle::expr_use_visitor;
17 use mc = middle::mem_categorization;
18 use middle::ty;
19 use syntax::codemap::Span;
20 use util::ppaux::Repr;
21
22 use std::rc::Rc;
23
24 pub enum RestrictionResult {
25 Safe,
26 SafeIf(Rc<LoanPath>, Vec<Restriction>)
27 }
28
29 pub fn compute_restrictions(bccx: &BorrowckCtxt,
30 span: Span,
31 cause: euv::LoanCause,
32 cmt: mc::cmt,
33 loan_region: ty::Region,
34 restr: RestrictionSet) -> RestrictionResult {
35 let ctxt = RestrictionsContext {
36 bccx: bccx,
37 span: span,
38 cause: cause,
39 cmt_original: cmt.clone(),
40 loan_region: loan_region,
41 };
42
43 ctxt.restrict(cmt, restr)
44 }
45
46 ///////////////////////////////////////////////////////////////////////////
47 // Private
48
49 struct RestrictionsContext<'a> {
50 bccx: &'a BorrowckCtxt<'a>,
51 span: Span,
52 cmt_original: mc::cmt,
53 loan_region: ty::Region,
54 cause: euv::LoanCause,
55 }
56
57 impl<'a> RestrictionsContext<'a> {
58 fn restrict(&self,
59 cmt: mc::cmt,
60 restrictions: RestrictionSet) -> RestrictionResult {
61 debug!("restrict(cmt={}, restrictions={})",
62 cmt.repr(self.bccx.tcx),
63 restrictions.repr(self.bccx.tcx));
64
65 match cmt.cat.clone() {
66 mc::cat_rvalue(..) => {
67 // Effectively, rvalues are stored into a
68 // non-aliasable temporary on the stack. Since they
69 // are inherently non-aliasable, they can only be
70 // accessed later through the borrow itself and hence
71 // must inherently comply with its terms.
72 Safe
73 }
74
75 mc::cat_local(local_id) |
76 mc::cat_arg(local_id) |
77 mc::cat_upvar(ty::UpvarId {var_id: local_id, ..}, _) => {
78 // R-Variable
79 let lp = Rc::new(LpVar(local_id));
80 SafeIf(lp.clone(), vec!(Restriction {
81 loan_path: lp,
82 set: restrictions
83 }))
84 }
85
86 mc::cat_downcast(cmt_base) => {
87 // When we borrow the interior of an enum, we have to
88 // ensure the enum itself is not mutated, because that
89 // could cause the type of the memory to change.
90 self.restrict(
91 cmt_base,
92 restrictions | RESTR_MUTATE)
93 }
94
95 mc::cat_interior(cmt_base, i) => {
96 // R-Field
97 //
98 // Overwriting the base would not change the type of
99 // the memory, so no additional restrictions are
100 // needed.
101 let result = self.restrict(cmt_base, restrictions);
102 self.extend(result, cmt.mutbl, LpInterior(i), restrictions)
103 }
104
105 mc::cat_deref(cmt_base, _, pk @ mc::OwnedPtr) |
106 mc::cat_deref(cmt_base, _, pk @ mc::GcPtr) => {
107 // R-Deref-Send-Pointer
108 //
109 // When we borrow the interior of an owned pointer, we
110 // cannot permit the base to be mutated, because that
111 // would cause the unique pointer to be freed.
112 //
113 // For a managed pointer, the rules are basically the
114 // same, because this could be the last ref.
115 // Eventually we should make these non-special and
116 // just rely on Deref<T> implementation.
117 let result = self.restrict(
118 cmt_base,
119 restrictions | RESTR_MUTATE);
120 self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
121 }
122
123 mc::cat_copied_upvar(..) | // FIXME(#2152) allow mutation of upvars
124 mc::cat_static_item(..) => {
125 Safe
126 }
127
128 mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::ImmBorrow, lt)) |
129 mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::UniqueImmBorrow, lt)) => {
130 // R-Deref-Imm-Borrowed
131 if !self.bccx.is_subregion_of(self.loan_region, lt) {
132 self.bccx.report(
133 BckError {
134 span: self.span,
135 cause: self.cause,
136 cmt: cmt_base,
137 code: err_borrowed_pointer_too_short(
138 self.loan_region, lt, restrictions)});
139 return Safe;
140 }
141 Safe
142 }
143
144 mc::cat_deref(cmt_base, _, pk @ mc::BorrowedPtr(ty::MutBorrow, lt)) => {
145 // R-Deref-Mut-Borrowed
146 if !self.bccx.is_subregion_of(self.loan_region, lt) {
147 self.bccx.report(
148 BckError {
149 span: self.span,
150 cause: self.cause,
151 cmt: cmt_base,
152 code: err_borrowed_pointer_too_short(
153 self.loan_region, lt, restrictions)});
154 return Safe;
155 }
156
157 let result = self.restrict(cmt_base, restrictions);
158 self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
159 }
160
161 mc::cat_deref(_, _, mc::UnsafePtr(..)) => {
162 // We are very trusting when working with unsafe pointers.
163 Safe
164 }
165
166 mc::cat_discr(cmt_base, _) => {
167 self.restrict(cmt_base, restrictions)
168 }
169 }
170 }
171
172 fn extend(&self,
173 result: RestrictionResult,
174 mc: mc::MutabilityCategory,
175 elem: LoanPathElem,
176 restrictions: RestrictionSet) -> RestrictionResult {
177 match result {
178 Safe => Safe,
179 SafeIf(base_lp, mut base_vec) => {
180 let lp = Rc::new(LpExtend(base_lp, mc, elem));
181 base_vec.push(Restriction {
182 loan_path: lp.clone(),
183 set: restrictions
184 });
185 SafeIf(lp, base_vec)
186 }
187 }
188 }
189 }
librustc/middle/borrowck/gather_loans/restrictions.rs:23:1-23:1 -enum- definition:
pub enum RestrictionResult {
Safe,
SafeIf(Rc<LoanPath>, Vec<Restriction>)
references:- 433: loan_region: ty::Region,
34: restr: RestrictionSet) -> RestrictionResult {
35: let ctxt = RestrictionsContext {
--
172: fn extend(&self,
173: result: RestrictionResult,
174: mc: mc::MutabilityCategory,
175: elem: LoanPathElem,
176: restrictions: RestrictionSet) -> RestrictionResult {
177: match result {
librustc/middle/borrowck/gather_loans/restrictions.rs:48:1-48:1 -struct- definition:
struct RestrictionsContext<'a> {
bccx: &'a BorrowckCtxt<'a>,
span: Span,
references:- 257: impl<'a> RestrictionsContext<'a> {
58: fn restrict(&self,