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.
14 use rustc::middle::expr_use_visitor as euv;
15 use rustc::middle::mem_categorization as mc;
16 use rustc::middle::mem_categorization::Categorization;
20 use borrowck::ToInteriorKind;
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: &'tcx 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: &'tcx 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);
61 let new_lp = |v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty));
63 match cmt.cat.clone() {
64 Categorization::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.
70 RestrictionResult::Safe
73 Categorization::Local(local_id) => {
74 // R-Variable, locally declared
75 let lp = new_lp(LpVar(local_id));
76 RestrictionResult::SafeIf(lp.clone(), vec![lp])
79 Categorization::Upvar(mc::Upvar { id, .. }) => {
80 // R-Variable, captured into closure
81 let lp = new_lp(LpUpvar(id));
82 RestrictionResult::SafeIf(lp.clone(), vec![lp])
85 Categorization::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 Categorization::Interior(cmt_base, i) => {
95 // Overwriting the base would not change the type of
96 // the memory, so no additional restrictions are
98 let opt_variant_id = match cmt_base.cat {
99 Categorization::Downcast(_, variant_id) => Some(variant_id),
102 let result = self.restrict(cmt_base);
103 self.extend(result, &cmt, LpInterior(opt_variant_id, i.cleaned()))
106 Categorization::StaticItem => {
107 RestrictionResult::Safe
110 Categorization::Deref(cmt_base, _, pk) => {
113 // R-Deref-Send-Pointer
115 // When we borrow the interior of a box, 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) {
130 cause: BorrowViolation(self.cause),
132 code: err_borrowed_pointer_too_short(
133 self.loan_region, lt)});
134 return RestrictionResult::Safe;
138 ty::ImmBorrow => RestrictionResult::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 raw pointers
151 mc::UnsafePtr(..) => RestrictionResult::Safe
158 result: RestrictionResult<'tcx>,
160 elem: LoanPathElem<'tcx>) -> RestrictionResult<'tcx> {
162 RestrictionResult::Safe => RestrictionResult::Safe,
163 RestrictionResult::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());
167 RestrictionResult::SafeIf(lp, base_vec)