Skip to main content

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
9impl<'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.
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}