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