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.
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.
12 * Computes the restrictions that result from a borrow.
15 pub use self::RestrictionResult::*;
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;
23 use syntax::codemap::Span;
24 use util::ppaux::Repr;
29 pub enum RestrictionResult<'tcx> {
31 SafeIf(Rc<LoanPath<'tcx>>, Vec<Rc<LoanPath<'tcx>>>)
34 pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
36 cause: euv::LoanCause,
38 loan_region: ty::Region)
39 -> RestrictionResult<'tcx> {
40 let ctxt = RestrictionsContext {
44 loan_region: loan_region,
50 ///////////////////////////////////////////////////////////////////////////
53 struct RestrictionsContext<'a, 'tcx: 'a> {
54 bccx: &'a BorrowckCtxt<'a, 'tcx>,
56 loan_region: ty::Region,
57 cause: euv::LoanCause,
60 impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
62 cmt: mc::cmt<'tcx>) -> RestrictionResult<'tcx> {
63 debug!("restrict(cmt={})", cmt.repr(self.bccx.tcx));
65 let new_lp = |v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty));
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.
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])
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])
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)
96 mc::cat_interior(cmt_base, i) => {
99 // Overwriting the base would not change the type of
100 // the memory, so no additional restrictions are
102 let result = self.restrict(cmt_base);
103 self.extend(result, &cmt, LpInterior(i))
106 mc::cat_static_item(..) => {
110 mc::cat_deref(cmt_base, _, pk) => {
113 // R-Deref-Send-Pointer
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.
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))
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) {
132 code: err_borrowed_pointer_too_short(
133 self.loan_region, lt)});
138 ty::ImmBorrow => Safe,
139 ty::MutBorrow | ty::UniqueImmBorrow => {
140 // R-Deref-Mut-Borrowed
142 // The referent can be aliased after the
143 // references lifetime ends (by a newly-unfrozen
145 let result = self.restrict(cmt_base);
146 self.extend(result, &cmt, LpDeref(pk))
150 // Borrowck is not relevant for unsafe pointers
151 mc::UnsafePtr(..) => Safe
158 result: RestrictionResult<'tcx>,
160 elem: LoanPathElem) -> RestrictionResult<'tcx> {
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());