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