• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #![deny(rustc::untranslatable_diagnostic)]
2 #![deny(rustc::diagnostic_outside_of_impl)]
3 use crate::borrow_set::LocalsStateAtExit;
4 use rustc_hir as hir;
5 use rustc_middle::mir::ProjectionElem;
6 use rustc_middle::mir::{Body, Mutability, Place};
7 use rustc_middle::ty::{self, TyCtxt};
8 
9 /// Extension methods for the `Place` type.
10 pub trait PlaceExt<'tcx> {
11     /// Returns `true` if we can safely ignore borrows of this place.
12     /// This is true whenever there is no action that the user can do
13     /// to the place `self` that would invalidate the borrow. This is true
14     /// for borrows of raw pointer dereferents as well as shared references.
ignore_borrow( &self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>, locals_state_at_exit: &LocalsStateAtExit, ) -> bool15     fn ignore_borrow(
16         &self,
17         tcx: TyCtxt<'tcx>,
18         body: &Body<'tcx>,
19         locals_state_at_exit: &LocalsStateAtExit,
20     ) -> bool;
21 }
22 
23 impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
ignore_borrow( &self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>, locals_state_at_exit: &LocalsStateAtExit, ) -> bool24     fn ignore_borrow(
25         &self,
26         tcx: TyCtxt<'tcx>,
27         body: &Body<'tcx>,
28         locals_state_at_exit: &LocalsStateAtExit,
29     ) -> bool {
30         // If a local variable is immutable, then we only need to track borrows to guard
31         // against two kinds of errors:
32         // * The variable being dropped while still borrowed (e.g., because the fn returns
33         //   a reference to a local variable)
34         // * The variable being moved while still borrowed
35         //
36         // In particular, the variable cannot be mutated -- the "access checks" will fail --
37         // so we don't have to worry about mutation while borrowed.
38         if let LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } =
39             locals_state_at_exit
40         {
41             let ignore = !has_storage_dead_or_moved.contains(self.local)
42                 && body.local_decls[self.local].mutability == Mutability::Not;
43             debug!("ignore_borrow: local {:?} => {:?}", self.local, ignore);
44             if ignore {
45                 return true;
46             }
47         }
48 
49         for (i, (proj_base, elem)) in self.iter_projections().enumerate() {
50             if elem == ProjectionElem::Deref {
51                 let ty = proj_base.ty(body, tcx).ty;
52                 match ty.kind() {
53                     ty::Ref(_, _, hir::Mutability::Not) if i == 0 => {
54                         // For references to thread-local statics, we do need
55                         // to track the borrow.
56                         if body.local_decls[self.local].is_ref_to_thread_local() {
57                             continue;
58                         }
59                         return true;
60                     }
61                     ty::RawPtr(..) | ty::Ref(_, _, hir::Mutability::Not) => {
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                     _ => {}
75                 }
76             }
77         }
78 
79         false
80     }
81 }
82