1use rustc_hiras hir;
2use rustc_macros::extension;
3use rustc_middle::mir::{Body, Mutability, Place, ProjectionElem};
4use rustc_middle::ty::{self, TyCtxt};
5use tracing::debug;
67use crate::borrow_set::LocalsStateAtExit;
89impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
#[doc = " Returns `true` if we can safely ignore borrows of this place."]
#[doc = " This is true whenever there is no action that the user can do"]
#[doc =
" to the place `self` that would invalidate the borrow. This is true"]
#[doc =
" 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 {
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;
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/place_ext.rs:34",
"rustc_borrowck::place_ext", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/place_ext.rs"),
::tracing_core::__macro_support::Option::Some(34u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::place_ext"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("ignore_borrow: local {0:?} => {1:?}",
self.local, ignore) as &dyn Value))])
});
} else { ; }
};
if ignore { return true; }
}
for (i, (proj_base, elem)) in self.iter_projections().enumerate() {
if elem == ProjectionElem::Deref {
let ty = proj_base.ty(body, tcx).ty;
match ty.kind() {
ty::Ref(_, _, hir::Mutability::Not) if i == 0 => {
if body.local_decls[self.local].is_ref_to_thread_local() {
continue;
}
return true;
}
ty::RawPtr(..) | ty::Ref(_, _, hir::Mutability::Not) => {
return true;
}
_ => {}
}
}
}
false
}
}#[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.
15fn 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.
29if let LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } =
30locals_state_at_exit31 {
32let ignore = !has_storage_dead_or_moved.contains(self.local)
33 && body.local_decls[self.local].mutability == Mutability::Not;
34debug!("ignore_borrow: local {:?} => {:?}", self.local, ignore);
35if ignore {
36return true;
37 }
38 }
3940for (i, (proj_base, elem)) in self.iter_projections().enumerate() {
41if elem == ProjectionElem::Deref {
42let ty = proj_base.ty(body, tcx).ty;
43match 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.
47if body.local_decls[self.local].is_ref_to_thread_local() {
48continue;
49 }
50return 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.
63return true;
64 }
65_ => {}
66 }
67 }
68 }
6970false
71}
72}