]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/borrowck/gather_loans/restrictions.rs
adae34b49dca2d1dc386c27f14a0f6f656ef3164
[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 pub use self::RestrictionResult::*;
16
17 use middle::borrowck::*;
18 use middle::borrowck::LoanPathElem::*;
19 use middle::borrowck::LoanPathKind::*;
20 use middle::expr_use_visitor as euv;
21 use middle::mem_categorization as mc;
22 use middle::ty;
23 use syntax::codemap::Span;
24 use util::ppaux::Repr;
25
26 use std::rc::Rc;
27
28 #[deriving(Show)]
29 pub enum RestrictionResult<'tcx> {
30     Safe,
31     SafeIf(Rc<LoanPath<'tcx>>, Vec<Rc<LoanPath<'tcx>>>)
32 }
33
34 pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
35                                       span: Span,
36                                       cause: euv::LoanCause,
37                                       cmt: mc::cmt<'tcx>,
38                                       loan_region: ty::Region)
39                                       -> RestrictionResult<'tcx> {
40     let ctxt = RestrictionsContext {
41         bccx: bccx,
42         span: span,
43         cause: cause,
44         loan_region: loan_region,
45     };
46
47     ctxt.restrict(cmt)
48 }
49
50 ///////////////////////////////////////////////////////////////////////////
51 // Private
52
53 struct RestrictionsContext<'a, 'tcx: 'a> {
54     bccx: &'a BorrowckCtxt<'a, 'tcx>,
55     span: Span,
56     loan_region: ty::Region,
57     cause: euv::LoanCause,
58 }
59
60 impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
61     fn restrict(&self,
62                 cmt: mc::cmt<'tcx>) -> RestrictionResult<'tcx> {
63         debug!("restrict(cmt={})", cmt.repr(self.bccx.tcx));
64
65         let new_lp = |v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty));
66
67         match cmt.cat.clone() {
68             mc::cat_rvalue(..) => {
69                 // Effectively, rvalues are stored into a
70                 // non-aliasable temporary on the stack. Since they
71                 // are inherently non-aliasable, they can only be
72                 // accessed later through the borrow itself and hence
73                 // must inherently comply with its terms.
74                 Safe
75             }
76
77             mc::cat_local(local_id) => {
78                 // R-Variable, locally declared
79                 let lp = new_lp(LpVar(local_id));
80                 SafeIf(lp.clone(), vec![lp])
81             }
82
83             mc::cat_upvar(mc::Upvar { id, .. }) => {
84                 // R-Variable, captured into closure
85                 let lp = new_lp(LpUpvar(id));
86                 SafeIf(lp.clone(), vec![lp])
87             }
88
89             mc::cat_downcast(cmt_base, _) => {
90                 // When we borrow the interior of an enum, we have to
91                 // ensure the enum itself is not mutated, because that
92                 // could cause the type of the memory to change.
93                 self.restrict(cmt_base)
94             }
95
96             mc::cat_interior(cmt_base, i) => {
97                 // R-Field
98                 //
99                 // Overwriting the base would not change the type of
100                 // the memory, so no additional restrictions are
101                 // needed.
102                 let result = self.restrict(cmt_base);
103                 self.extend(result, &cmt, LpInterior(i))
104             }
105
106             mc::cat_static_item(..) => {
107                 Safe
108             }
109
110             mc::cat_deref(cmt_base, _, pk) => {
111                 match pk {
112                     mc::OwnedPtr => {
113                         // R-Deref-Send-Pointer
114                         //
115                         // When we borrow the interior of an owned pointer, we
116                         // cannot permit the base to be mutated, because that
117                         // would cause the unique pointer to be freed.
118                         //
119                         // Eventually we should make these non-special and
120                         // just rely on Deref<T> implementation.
121                         let result = self.restrict(cmt_base);
122                         self.extend(result, &cmt, LpDeref(pk))
123                     }
124                     mc::Implicit(bk, lt) | mc::BorrowedPtr(bk, lt) => {
125                         // R-Deref-[Mut-]Borrowed
126                         if !self.bccx.is_subregion_of(self.loan_region, lt) {
127                             self.bccx.report(
128                                 BckError {
129                                     span: self.span,
130                                     cause: self.cause,
131                                     cmt: cmt_base,
132                                     code: err_borrowed_pointer_too_short(
133                                         self.loan_region, lt)});
134                             return Safe;
135                         }
136
137                         match bk {
138                             ty::ImmBorrow => Safe,
139                             ty::MutBorrow | ty::UniqueImmBorrow => {
140                                 // R-Deref-Mut-Borrowed
141                                 //
142                                 // The referent can be aliased after the
143                                 // references lifetime ends (by a newly-unfrozen
144                                 // borrow).
145                                 let result = self.restrict(cmt_base);
146                                 self.extend(result, &cmt, LpDeref(pk))
147                             }
148                         }
149                     }
150                     // Borrowck is not relevant for unsafe pointers
151                     mc::UnsafePtr(..) => Safe
152                 }
153             }
154         }
155     }
156
157     fn extend(&self,
158               result: RestrictionResult<'tcx>,
159               cmt: &mc::cmt<'tcx>,
160               elem: LoanPathElem) -> RestrictionResult<'tcx> {
161         match result {
162             Safe => Safe,
163             SafeIf(base_lp, mut base_vec) => {
164                 let v = LpExtend(base_lp, cmt.mutbl, elem);
165                 let lp = Rc::new(LoanPath::new(v, cmt.ty));
166                 base_vec.push(lp.clone());
167                 SafeIf(lp, base_vec)
168             }
169         }
170     }
171 }