]>
Commit | Line | Data |
---|---|---|
c295e0f8 | 1 | use crate::borrow_set::LocalsStateAtExit; |
dfeec247 | 2 | use rustc_hir as hir; |
c620b35d | 3 | use rustc_macros::extension; |
ba9703b0 XL |
4 | use rustc_middle::mir::ProjectionElem; |
5 | use rustc_middle::mir::{Body, Mutability, Place}; | |
6 | use rustc_middle::ty::{self, TyCtxt}; | |
83c7162d | 7 | |
c620b35d FG |
8 | #[extension(pub trait PlaceExt<'tcx>)] |
9 | impl<'tcx> Place<'tcx> { | |
9fa01778 | 10 | /// Returns `true` if we can safely ignore borrows of this place. |
b7449926 XL |
11 | /// This is true whenever there is no action that the user can do |
12 | /// to the place `self` that would invalidate the borrow. This is true | |
13 | /// for borrows of raw pointer dereferents as well as shared references. | |
b7449926 XL |
14 | fn ignore_borrow( |
15 | &self, | |
dc9dc135 XL |
16 | tcx: TyCtxt<'tcx>, |
17 | body: &Body<'tcx>, | |
b7449926 XL |
18 | locals_state_at_exit: &LocalsStateAtExit, |
19 | ) -> bool { | |
dfeec247 XL |
20 | // If a local variable is immutable, then we only need to track borrows to guard |
21 | // against two kinds of errors: | |
22 | // * The variable being dropped while still borrowed (e.g., because the fn returns | |
23 | // a reference to a local variable) | |
24 | // * The variable being moved while still borrowed | |
25 | // | |
26 | // In particular, the variable cannot be mutated -- the "access checks" will fail -- | |
27 | // so we don't have to worry about mutation while borrowed. | |
28 | if let LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } = | |
29 | locals_state_at_exit | |
30 | { | |
31 | let ignore = !has_storage_dead_or_moved.contains(self.local) | |
32 | && body.local_decls[self.local].mutability == Mutability::Not; | |
33 | debug!("ignore_borrow: local {:?} => {:?}", self.local, ignore); | |
34 | if ignore { | |
35 | return true; | |
e1599b0c | 36 | } |
dfeec247 | 37 | } |
b7449926 | 38 | |
fe692bf9 | 39 | for (i, (proj_base, elem)) in self.iter_projections().enumerate() { |
f9f354fc | 40 | if elem == ProjectionElem::Deref { |
fe692bf9 | 41 | let ty = proj_base.ty(body, tcx).ty; |
1b1a35ee | 42 | match ty.kind() { |
dfeec247 | 43 | ty::Ref(_, _, hir::Mutability::Not) if i == 0 => { |
60c5eb7d XL |
44 | // For references to thread-local statics, we do need |
45 | // to track the borrow. | |
dfeec247 | 46 | if body.local_decls[self.local].is_ref_to_thread_local() { |
60c5eb7d XL |
47 | continue; |
48 | } | |
49 | return true; | |
50 | } | |
dfeec247 | 51 | ty::RawPtr(..) | ty::Ref(_, _, hir::Mutability::Not) => { |
60c5eb7d XL |
52 | // For both derefs of raw pointers and `&T` |
53 | // references, the original path is `Copy` and | |
9c376795 | 54 | // therefore not significant. In particular, |
60c5eb7d XL |
55 | // there is nothing the user can do to the |
56 | // original path that would invalidate the | |
57 | // newly created reference -- and if there | |
58 | // were, then the user could have copied the | |
59 | // original path into a new variable and | |
60 | // borrowed *that* one, leaving the original | |
61 | // path unborrowed. | |
62 | return true; | |
63 | } | |
64 | _ => {} | |
83c7162d | 65 | } |
dc9dc135 | 66 | } |
e1599b0c | 67 | } |
dc9dc135 | 68 | |
60c5eb7d | 69 | false |
83c7162d | 70 | } |
83c7162d | 71 | } |