]> git.lizzy.rs Git - rust.git/blob - src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
Changed issue number to 36105
[rust.git] / src / librustc_borrowck / borrowck / gather_loans / restrictions.rs
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.
4 //
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.
10
11 //! Computes the restrictions that result from a borrow.
12
13 use borrowck::*;
14 use rustc::middle::expr_use_visitor as euv;
15 use rustc::middle::mem_categorization as mc;
16 use rustc::middle::mem_categorization::Categorization;
17 use rustc::ty;
18 use syntax_pos::Span;
19
20 use borrowck::ToInteriorKind;
21
22 use std::rc::Rc;
23
24 #[derive(Debug)]
25 pub enum RestrictionResult<'tcx> {
26     Safe,
27     SafeIf(Rc<LoanPath<'tcx>>, Vec<Rc<LoanPath<'tcx>>>)
28 }
29
30 pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
31                                       span: Span,
32                                       cause: euv::LoanCause,
33                                       cmt: mc::cmt<'tcx>,
34                                       loan_region: ty::Region)
35                                       -> RestrictionResult<'tcx> {
36     let ctxt = RestrictionsContext {
37         bccx: bccx,
38         span: span,
39         cause: cause,
40         loan_region: loan_region,
41     };
42
43     ctxt.restrict(cmt)
44 }
45
46 ///////////////////////////////////////////////////////////////////////////
47 // Private
48
49 struct RestrictionsContext<'a, 'tcx: 'a> {
50     bccx: &'a BorrowckCtxt<'a, 'tcx>,
51     span: Span,
52     loan_region: ty::Region,
53     cause: euv::LoanCause,
54 }
55
56 impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
57     fn restrict(&self,
58                 cmt: mc::cmt<'tcx>) -> RestrictionResult<'tcx> {
59         debug!("restrict(cmt={:?})", cmt);
60
61         let new_lp = |v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty));
62
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
71             }
72
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])
77             }
78
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])
83             }
84
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)
90             }
91
92             Categorization::Interior(cmt_base, i) => {
93                 // R-Field
94                 //
95                 // Overwriting the base would not change the type of
96                 // the memory, so no additional restrictions are
97                 // needed.
98                 let opt_variant_id = match cmt_base.cat {
99                     Categorization::Downcast(_, variant_id) => Some(variant_id),
100                     _ => None
101                 };
102                 let result = self.restrict(cmt_base);
103                 self.extend(result, &cmt, LpInterior(opt_variant_id, i.cleaned()))
104             }
105
106             Categorization::StaticItem => {
107                 RestrictionResult::Safe
108             }
109
110             Categorization::Deref(cmt_base, _, pk) => {
111                 match pk {
112                     mc::Unique => {
113                         // R-Deref-Send-Pointer
114                         //
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.
118                         //
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))
123                     }
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) {
127                             self.bccx.report(
128                                 BckError {
129                                     span: self.span,
130                                     cause: BorrowViolation(self.cause),
131                                     cmt: cmt_base,
132                                     code: err_borrowed_pointer_too_short(
133                                         self.loan_region, lt)});
134                             return RestrictionResult::Safe;
135                         }
136
137                         match bk {
138                             ty::ImmBorrow => RestrictionResult::Safe,
139                             ty::MutBorrow | ty::UniqueImmBorrow => {
140                                 // R-Deref-Mut-Borrowed
141                                 //
142                                 // The referent can be aliased after the
143                                 // references lifetime ends (by a newly-unfrozen
144                                 // borrow).
145                                 let result = self.restrict(cmt_base);
146                                 self.extend(result, &cmt, LpDeref(pk))
147                             }
148                         }
149                     }
150                     // Borrowck is not relevant for raw pointers
151                     mc::UnsafePtr(..) => RestrictionResult::Safe
152                 }
153             }
154         }
155     }
156
157     fn extend(&self,
158               result: RestrictionResult<'tcx>,
159               cmt: &mc::cmt<'tcx>,
160               elem: LoanPathElem) -> RestrictionResult<'tcx> {
161         match result {
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)
168             }
169         }
170     }
171 }