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