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