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