Skip to content

Commit

Permalink
Rollup merge of rust-lang#64005 - ecstatic-morse:is-indirect, r=oli-obk
Browse files Browse the repository at this point in the history
Add a `Place::is_indirect` method to determine whether a `Place` contains a `Deref` projection

Working on rust-lang#63860 requires tracking some property about each local. This requires differentiating `Place`s like `x` and `x.field[index]` from ones like `*x` and `*x.field`, since the first two will always access the same region of memory as `x` while the latter two may access any region of memory. This functionality is duplicated in various places across the compiler. This PR adds a helper method to `Place` which determines whether that `Place` has a `Deref` projection at any point and changes some existing code to use the new method.

I've not converted `qualify_consts.rs` to use the new method, since it's not a trivial conversion and it will get replaced anyway by rust-lang#63860. There may be other potential uses besides the two I change in this PR.

r? @oli-obk
  • Loading branch information
Centril authored Sep 5, 2019
2 parents a721221 + 96ac02b commit 77a033a
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 29 deletions.
25 changes: 25 additions & 0 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1808,6 +1808,23 @@ pub enum ProjectionElem<V, T> {
Downcast(Option<Symbol>, VariantIdx),
}

impl<V, T> ProjectionElem<V, T> {
/// Returns `true` if the target of this projection may refer to a different region of memory
/// than the base.
fn is_indirect(&self) -> bool {
match self {
Self::Deref => true,

| Self::Field(_, _)
| Self::Index(_)
| Self::ConstantIndex { .. }
| Self::Subslice { .. }
| Self::Downcast(_, _)
=> false
}
}
}

/// Alias for projections as they appear in places, where the base is a place
/// and the index is a local.
pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>;
Expand Down Expand Up @@ -1869,6 +1886,14 @@ impl<'tcx> Place<'tcx> {
}
}

/// Returns `true` if this `Place` contains a `Deref` projection.
///
/// If `Place::is_indirect` returns false, the caller knows that the `Place` refers to the
/// same region of memory as its base.
pub fn is_indirect(&self) -> bool {
self.iterate(|_, mut projections| projections.any(|proj| proj.elem.is_indirect()))
}

/// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
/// a single deref of a local.
//
Expand Down
23 changes: 7 additions & 16 deletions src/librustc_mir/borrow_check/path_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::borrow_check::places_conflict;
use crate::borrow_check::AccessDepth;
use crate::dataflow::indexes::BorrowIndex;
use rustc::mir::{BasicBlock, Location, Body, Place, PlaceBase};
use rustc::mir::{ProjectionElem, BorrowKind};
use rustc::mir::BorrowKind;
use rustc::ty::{self, TyCtxt};
use rustc_data_structures::graph::dominators::Dominators;

Expand Down Expand Up @@ -133,20 +133,11 @@ pub(super) fn is_active<'tcx>(
/// Determines if a given borrow is borrowing local data
/// This is called for all Yield statements on movable generators
pub(super) fn borrow_of_local_data(place: &Place<'_>) -> bool {
place.iterate(|place_base, place_projection| {
match place_base {
PlaceBase::Static(..) => return false,
PlaceBase::Local(..) => {},
}

for proj in place_projection {
// Reborrow of already borrowed data is ignored
// Any errors will be caught on the initial borrow
if proj.elem == ProjectionElem::Deref {
return false;
}
}
match place.base {
PlaceBase::Static(_) => false,

true
})
// Reborrow of already borrowed data is ignored
// Any errors will be caught on the initial borrow
PlaceBase::Local(_) => !place.is_indirect(),
}
}
17 changes: 4 additions & 13 deletions src/librustc_mir/dataflow/impls/borrowed_locals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,10 @@ struct BorrowedLocalsVisitor<'gk> {
}

fn find_local(place: &Place<'_>) -> Option<Local> {
place.iterate(|place_base, place_projection| {
for proj in place_projection {
if proj.elem == ProjectionElem::Deref {
return None;
}
}

if let PlaceBase::Local(local) = place_base {
Some(*local)
} else {
None
}
})
match place.base {
PlaceBase::Local(local) if !place.is_indirect() => Some(local),
_ => None,
}
}

impl<'tcx> Visitor<'tcx> for BorrowedLocalsVisitor<'_> {
Expand Down

0 comments on commit 77a033a

Please sign in to comment.