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