]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/borrowck/gather_loans/restrictions.rs
Doc says to avoid mixing allocator instead of forbiding it
[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 middle::borrowck::*;
16 use middle::expr_use_visitor as euv;
17 use middle::mem_categorization as mc;
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<Rc<LoanPath>>)
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) -> RestrictionResult {
34     let ctxt = RestrictionsContext {
35         bccx: bccx,
36         span: span,
37         cause: cause,
38         loan_region: loan_region,
39     };
40
41     ctxt.restrict(cmt)
42 }
43
44 ///////////////////////////////////////////////////////////////////////////
45 // Private
46
47 struct RestrictionsContext<'a, 'tcx: 'a> {
48     bccx: &'a BorrowckCtxt<'a, 'tcx>,
49     span: Span,
50     loan_region: ty::Region,
51     cause: euv::LoanCause,
52 }
53
54 impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
55     fn restrict(&self,
56                 cmt: mc::cmt) -> RestrictionResult {
57         debug!("restrict(cmt={})", cmt.repr(self.bccx.tcx));
58
59         match cmt.cat.clone() {
60             mc::cat_rvalue(..) => {
61                 // Effectively, rvalues are stored into a
62                 // non-aliasable temporary on the stack. Since they
63                 // are inherently non-aliasable, they can only be
64                 // accessed later through the borrow itself and hence
65                 // must inherently comply with its terms.
66                 Safe
67             }
68
69             mc::cat_local(local_id) |
70             mc::cat_arg(local_id) => {
71                 // R-Variable, locally declared
72                 let lp = Rc::new(LpVar(local_id));
73                 SafeIf(lp.clone(), vec![lp])
74             }
75
76             mc::cat_upvar(upvar_id, _) => {
77                 // R-Variable, captured into closure
78                 let lp = Rc::new(LpUpvar(upvar_id));
79                 SafeIf(lp.clone(), vec![lp])
80             }
81
82             mc::cat_copied_upvar(mc::CopiedUpvar { upvar_id, .. }) => {
83                 // R-Variable, copied/moved into closure
84                 let lp = Rc::new(LpVar(upvar_id));
85                 SafeIf(lp.clone(), vec![lp])
86             }
87
88             mc::cat_downcast(cmt_base) => {
89                 // When we borrow the interior of an enum, we have to
90                 // ensure the enum itself is not mutated, because that
91                 // could cause the type of the memory to change.
92                 self.restrict(cmt_base)
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);
102                 self.extend(result, cmt.mutbl, LpInterior(i))
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(cmt_base);
118                 self.extend(result, cmt.mutbl, LpDeref(pk))
119             }
120
121             mc::cat_static_item(..) => {
122                 Safe
123             }
124
125             mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::ImmBorrow, lt)) |
126             mc::cat_deref(cmt_base, _, mc::Implicit(ty::ImmBorrow, lt)) => {
127                 // R-Deref-Imm-Borrowed
128                 if !self.bccx.is_subregion_of(self.loan_region, lt) {
129                     self.bccx.report(
130                         BckError {
131                             span: self.span,
132                             cause: self.cause,
133                             cmt: cmt_base,
134                             code: err_borrowed_pointer_too_short(
135                                 self.loan_region, lt)});
136                     return Safe;
137                 }
138                 Safe
139             }
140
141             mc::cat_deref(cmt_base, _, pk) => {
142                 match pk {
143                     mc::BorrowedPtr(ty::MutBorrow, lt) |
144                     mc::BorrowedPtr(ty::UniqueImmBorrow, lt) |
145                     mc::Implicit(ty::MutBorrow, lt) |
146                     mc::Implicit(ty::UniqueImmBorrow, lt) => {
147                         // R-Deref-Mut-Borrowed
148                         if !self.bccx.is_subregion_of(self.loan_region, lt) {
149                             self.bccx.report(
150                                 BckError {
151                                     span: self.span,
152                                     cause: self.cause,
153                                     cmt: cmt_base,
154                                     code: err_borrowed_pointer_too_short(
155                                         self.loan_region, lt)});
156                             return Safe;
157                         }
158
159                         let result = self.restrict(cmt_base);
160                         self.extend(result, cmt.mutbl, LpDeref(pk))
161                     }
162                     mc::UnsafePtr(..) => {
163                         // We are very trusting when working with unsafe
164                         // pointers.
165                         Safe
166                     }
167                     _ => {
168                         self.bccx.tcx.sess.span_bug(self.span,
169                                                     "unhandled memcat in \
170                                                      cat_deref")
171                     }
172                 }
173             }
174
175             mc::cat_discr(cmt_base, _) => {
176                 self.restrict(cmt_base)
177             }
178         }
179     }
180
181     fn extend(&self,
182               result: RestrictionResult,
183               mc: mc::MutabilityCategory,
184               elem: LoanPathElem) -> RestrictionResult {
185         match result {
186             Safe => Safe,
187             SafeIf(base_lp, mut base_vec) => {
188                 let lp = Rc::new(LpExtend(base_lp, mc, elem));
189                 base_vec.push(lp.clone());
190                 SafeIf(lp, base_vec)
191             }
192         }
193     }
194 }