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