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 use middle::borrowck::*;
16 use middle::expr_use_visitor as euv;
17 use middle::mem_categorization as mc;
19 use syntax::codemap::Span;
20 use util::ppaux::Repr;
24 pub enum RestrictionResult {
26 SafeIf(Rc<LoanPath>, Vec<Rc<LoanPath>>)
29 pub fn compute_restrictions(bccx: &BorrowckCtxt,
31 cause: euv::LoanCause,
33 loan_region: ty::Region) -> RestrictionResult {
34 let ctxt = RestrictionsContext {
38 loan_region: loan_region,
44 ///////////////////////////////////////////////////////////////////////////
47 struct RestrictionsContext<'a, 'tcx: 'a> {
48 bccx: &'a BorrowckCtxt<'a, 'tcx>,
50 loan_region: ty::Region,
51 cause: euv::LoanCause,
54 impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
56 cmt: mc::cmt) -> RestrictionResult {
57 debug!("restrict(cmt={})", cmt.repr(self.bccx.tcx));
59 match cmt.cat.clone() {
60 mc::cat_rvalue(..) => {
61 // Effectively, rvalues are stored into a
62 // non-aliasable temporary on the stack. Since they
63 // are inherently non-aliasable, they can only be
64 // accessed later through the borrow itself and hence
65 // must inherently comply with its terms.
69 mc::cat_local(local_id) |
70 mc::cat_arg(local_id) => {
71 // R-Variable, locally declared
72 let lp = Rc::new(LpVar(local_id));
73 SafeIf(lp.clone(), vec![lp])
76 mc::cat_upvar(upvar_id, _) => {
77 // R-Variable, captured into closure
78 let lp = Rc::new(LpUpvar(upvar_id));
79 SafeIf(lp.clone(), vec![lp])
82 mc::cat_copied_upvar(mc::CopiedUpvar { upvar_id, .. }) => {
83 // R-Variable, copied/moved into closure
84 let lp = Rc::new(LpVar(upvar_id));
85 SafeIf(lp.clone(), vec![lp])
88 mc::cat_downcast(cmt_base) => {
89 // When we borrow the interior of an enum, we have to
90 // ensure the enum itself is not mutated, because that
91 // could cause the type of the memory to change.
92 self.restrict(cmt_base)
95 mc::cat_interior(cmt_base, i) => {
98 // Overwriting the base would not change the type of
99 // the memory, so no additional restrictions are
101 let result = self.restrict(cmt_base);
102 self.extend(result, cmt.mutbl, LpInterior(i))
105 mc::cat_deref(cmt_base, _, pk @ mc::OwnedPtr) |
106 mc::cat_deref(cmt_base, _, pk @ mc::GcPtr) => {
107 // R-Deref-Send-Pointer
109 // When we borrow the interior of an owned pointer, we
110 // cannot permit the base to be mutated, because that
111 // would cause the unique pointer to be freed.
113 // For a managed pointer, the rules are basically the
114 // same, because this could be the last ref.
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.mutbl, LpDeref(pk))
121 mc::cat_static_item(..) => {
125 mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::ImmBorrow, lt)) |
126 mc::cat_deref(cmt_base, _, mc::Implicit(ty::ImmBorrow, lt)) => {
127 // R-Deref-Imm-Borrowed
128 if !self.bccx.is_subregion_of(self.loan_region, lt) {
134 code: err_borrowed_pointer_too_short(
135 self.loan_region, lt)});
141 mc::cat_deref(cmt_base, _, pk) => {
143 mc::BorrowedPtr(ty::MutBorrow, lt) |
144 mc::BorrowedPtr(ty::UniqueImmBorrow, lt) |
145 mc::Implicit(ty::MutBorrow, lt) |
146 mc::Implicit(ty::UniqueImmBorrow, lt) => {
147 // R-Deref-Mut-Borrowed
148 if !self.bccx.is_subregion_of(self.loan_region, lt) {
154 code: err_borrowed_pointer_too_short(
155 self.loan_region, lt)});
159 let result = self.restrict(cmt_base);
160 self.extend(result, cmt.mutbl, LpDeref(pk))
162 mc::UnsafePtr(..) => {
163 // We are very trusting when working with unsafe
168 self.bccx.tcx.sess.span_bug(self.span,
169 "unhandled memcat in \
175 mc::cat_discr(cmt_base, _) => {
176 self.restrict(cmt_base)
182 result: RestrictionResult,
183 mc: mc::MutabilityCategory,
184 elem: LoanPathElem) -> RestrictionResult {
187 SafeIf(base_lp, mut base_vec) => {
188 let lp = Rc::new(LpExtend(base_lp, mc, elem));
189 base_vec.push(lp.clone());