diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index fe33dc0a58a4..2e0cbf4326bc 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -159,7 +159,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { location: mir::Location, ) { if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue { - if borrowed_place.is_unsafe_place(self.tcx, self.mir) { + if borrowed_place.ignore_borrow(self.tcx, self.mir) { return; } diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs index b0517c5e61f2..be0091068c2e 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/src/librustc_mir/borrow_check/place_ext.rs @@ -15,8 +15,11 @@ use rustc::ty::{self, TyCtxt}; /// Extension methods for the `Place` type. crate trait PlaceExt<'tcx> { - /// True if this is a deref of a raw pointer. - fn is_unsafe_place(&self, tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) -> bool; + /// 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>, mir: &Mir<'tcx>) -> bool; /// If this is a place like `x.f.g`, returns the local /// `x`. Returns `None` if this is based in a static. @@ -24,7 +27,7 @@ crate trait PlaceExt<'tcx> { } impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { - fn is_unsafe_place(&self, tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) -> bool { + fn ignore_borrow(&self, tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) -> bool { match self { Place::Promoted(_) | Place::Local(_) => false, @@ -36,12 +39,23 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { | ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Index(_) => proj.base.is_unsafe_place(tcx, mir), + | ProjectionElem::Index(_) => proj.base.ignore_borrow(tcx, mir), + ProjectionElem::Deref => { let ty = proj.base.ty(mir, tcx).to_ty(tcx); match ty.sty { - ty::TyRawPtr(..) => true, - _ => proj.base.is_unsafe_place(tcx, mir), + // 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. + ty::TyRawPtr(..) | ty::TyRef(_, _, hir::MutImmutable) => true, + _ => proj.base.ignore_borrow(tcx, mir), } } }, diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index ea59e42fd479..b0c4d37814e8 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -233,7 +233,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> { // propagate_call_return method. if let mir::Rvalue::Ref(region, _, ref place) = *rhs { - if place.is_unsafe_place(self.tcx, self.mir) { return; } + if place.ignore_borrow(self.tcx, self.mir) { return; } let index = self.borrow_set.location_map.get(&location).unwrap_or_else(|| { panic!("could not find BorrowIndex for location {:?}", location); });