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.
16 use middle::borrowck::*;
17 use mc = middle::mem_categorization;
19 use syntax::codemap::Span;
20 use util::ppaux::Repr;
22 pub enum RestrictionResult {
24 SafeIf(@LoanPath, ~[Restriction])
27 pub fn compute_restrictions(bccx: &BorrowckCtxt,
31 loan_region: ty::Region,
32 restr: RestrictionSet) -> RestrictionResult {
33 let ctxt = RestrictionsContext {
38 loan_region: loan_region,
41 ctxt.restrict(cmt, restr)
44 ///////////////////////////////////////////////////////////////////////////
47 struct RestrictionsContext<'a> {
48 bccx: &'a BorrowckCtxt,
50 cmt_original: mc::cmt,
51 loan_region: ty::Region,
55 impl<'a> RestrictionsContext<'a> {
58 restrictions: RestrictionSet) -> RestrictionResult {
59 debug!("restrict(cmt={}, restrictions={})",
60 cmt.repr(self.bccx.tcx),
61 restrictions.repr(self.bccx.tcx));
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.
73 mc::cat_local(local_id) |
74 mc::cat_arg(local_id) |
75 mc::cat_upvar(ty::UpvarId {var_id: local_id, ..}, _) => {
77 let lp = @LpVar(local_id);
78 SafeIf(lp, ~[Restriction {loan_path: lp,
82 mc::cat_downcast(cmt_base) => {
83 // When we borrow the interior of an enum, we have to
84 // ensure the enum itself is not mutated, because that
85 // could cause the type of the memory to change.
88 restrictions | RESTR_MUTATE)
91 mc::cat_interior(cmt_base, i) => {
94 // Overwriting the base would not change the type of
95 // the memory, so no additional restrictions are
97 let result = self.restrict(cmt_base, restrictions);
98 self.extend(result, cmt.mutbl, LpInterior(i), restrictions)
101 mc::cat_deref(cmt_base, _, pk @ mc::OwnedPtr) => {
102 // R-Deref-Send-Pointer
104 // When we borrow the interior of an owned pointer, we
105 // cannot permit the base to be mutated, because that
106 // would cause the unique pointer to be freed.
107 let result = self.restrict(
109 restrictions | RESTR_MUTATE);
110 self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
113 mc::cat_copied_upvar(..) | // FIXME(#2152) allow mutation of upvars
114 mc::cat_static_item(..) => {
118 mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::ImmBorrow, lt)) |
119 mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::UniqueImmBorrow, lt)) => {
120 // R-Deref-Imm-Borrowed
121 if !self.bccx.is_subregion_of(self.loan_region, lt) {
127 code: err_borrowed_pointer_too_short(
128 self.loan_region, lt, restrictions)});
134 mc::cat_deref(_, _, mc::GcPtr) => {
135 // R-Deref-Imm-Managed
139 mc::cat_deref(cmt_base, _, pk @ mc::BorrowedPtr(ty::MutBorrow, lt)) => {
140 // R-Deref-Mut-Borrowed
141 if !self.bccx.is_subregion_of(self.loan_region, lt) {
147 code: err_borrowed_pointer_too_short(
148 self.loan_region, lt, restrictions)});
152 let result = self.restrict(cmt_base, restrictions);
153 self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
156 mc::cat_deref(_, _, mc::UnsafePtr(..)) => {
157 // We are very trusting when working with unsafe pointers.
161 mc::cat_discr(cmt_base, _) => {
162 self.restrict(cmt_base, restrictions)
168 result: RestrictionResult,
169 mc: mc::MutabilityCategory,
171 restrictions: RestrictionSet) -> RestrictionResult {
174 SafeIf(base_lp, base_vec) => {
175 let lp = @LpExtend(base_lp, mc, elem);
176 SafeIf(lp, vec::append_one(base_vec,
177 Restriction {loan_path: lp,