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