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.
11 //! Computes the restrictions that result from a borrow.
13 pub use self::RestrictionResult::*;
16 use rustc::middle::expr_use_visitor as euv;
17 use rustc::middle::mem_categorization as mc;
18 use rustc::middle::ty;
19 use rustc::util::ppaux::Repr;
20 use syntax::codemap::Span;
25 pub enum RestrictionResult<'tcx> {
27 SafeIf(Rc<LoanPath<'tcx>>, Vec<Rc<LoanPath<'tcx>>>)
30 pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
32 cause: euv::LoanCause,
34 loan_region: ty::Region)
35 -> RestrictionResult<'tcx> {
36 let ctxt = RestrictionsContext {
40 loan_region: loan_region,
46 ///////////////////////////////////////////////////////////////////////////
49 struct RestrictionsContext<'a, 'tcx: 'a> {
50 bccx: &'a BorrowckCtxt<'a, 'tcx>,
52 loan_region: ty::Region,
53 cause: euv::LoanCause,
56 impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
58 cmt: mc::cmt<'tcx>) -> RestrictionResult<'tcx> {
59 debug!("restrict(cmt={})", cmt.repr(self.bccx.tcx));
61 let new_lp = |&: v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty));
63 match cmt.cat.clone() {
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 // R-Variable, locally declared
75 let lp = new_lp(LpVar(local_id));
76 SafeIf(lp.clone(), vec![lp])
79 mc::cat_upvar(mc::Upvar { id, .. }) => {
80 // R-Variable, captured into closure
81 let lp = new_lp(LpUpvar(id));
82 SafeIf(lp.clone(), vec![lp])
85 mc::cat_downcast(cmt_base, _) => {
86 // When we borrow the interior of an enum, we have to
87 // ensure the enum itself is not mutated, because that
88 // could cause the type of the memory to change.
89 self.restrict(cmt_base)
92 mc::cat_interior(cmt_base, i) => {
95 // Overwriting the base would not change the type of
96 // the memory, so no additional restrictions are
98 let result = self.restrict(cmt_base);
99 self.extend(result, &cmt, LpInterior(i))
102 mc::cat_static_item(..) => {
106 mc::cat_deref(cmt_base, _, pk) => {
109 // R-Deref-Send-Pointer
111 // When we borrow the interior of an owned pointer, we
112 // cannot permit the base to be mutated, because that
113 // would cause the unique pointer to be freed.
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, LpDeref(pk))
120 mc::Implicit(bk, lt) | mc::BorrowedPtr(bk, lt) => {
121 // R-Deref-[Mut-]Borrowed
122 if !self.bccx.is_subregion_of(self.loan_region, lt) {
128 code: err_borrowed_pointer_too_short(
129 self.loan_region, lt)});
134 ty::ImmBorrow => Safe,
135 ty::MutBorrow | ty::UniqueImmBorrow => {
136 // R-Deref-Mut-Borrowed
138 // The referent can be aliased after the
139 // references lifetime ends (by a newly-unfrozen
141 let result = self.restrict(cmt_base);
142 self.extend(result, &cmt, LpDeref(pk))
146 // Borrowck is not relevant for unsafe pointers
147 mc::UnsafePtr(..) => Safe
154 result: RestrictionResult<'tcx>,
156 elem: LoanPathElem) -> RestrictionResult<'tcx> {
159 SafeIf(base_lp, mut base_vec) => {
160 let v = LpExtend(base_lp, cmt.mutbl, elem);
161 let lp = Rc::new(LoanPath::new(v, cmt.ty));
162 base_vec.push(lp.clone());