Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Place::is_indirect method to determine whether a Place contains a Deref projection #64005

Merged
merged 2 commits into from
Sep 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1801,6 +1801,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 @@ -1862,6 +1879,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,
}
ecstatic-morse marked this conversation as resolved.
Show resolved Hide resolved
}

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