about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-09-05 03:59:37 +0200
committerGitHub <noreply@github.com>2019-09-05 03:59:37 +0200
commit9718f7a09fc9c5b97f8b2c873faf87ba86c11fc6 (patch)
tree143556b1e9f6ff0f837ff9407e860ea2fdc2c095
parentd1d511df8c56af39bc491afcd7e896ed4202fdd4 (diff)
parent96ac02b8b3aeebc463d434c57b4a2ada9a3003e6 (diff)
downloadrust-9718f7a09fc9c5b97f8b2c873faf87ba86c11fc6.tar.gz
rust-9718f7a09fc9c5b97f8b2c873faf87ba86c11fc6.zip
Rollup merge of #64005 - ecstatic-morse:is-indirect, r=oli-obk
Add a `Place::is_indirect` method to determine whether a `Place` contains a `Deref` projection

Working on #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 #63860. There may be other potential uses besides the two I change in this PR.

r? @oli-obk
-rw-r--r--src/librustc/mir/mod.rs25
-rw-r--r--src/librustc_mir/borrow_check/path_utils.rs23
-rw-r--r--src/librustc_mir/dataflow/impls/borrowed_locals.rs17
3 files changed, 36 insertions, 29 deletions
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 5ac99ba1470..8956cbb2bae 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -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>>;
@@ -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.
     //
diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs
index 43a012e1494..bac08090817 100644
--- a/src/librustc_mir/borrow_check/path_utils.rs
+++ b/src/librustc_mir/borrow_check/path_utils.rs
@@ -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;
 
@@ -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(),
+    }
 }
diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/src/librustc_mir/dataflow/impls/borrowed_locals.rs
index d94ebdbae24..1c43a553cc3 100644
--- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs
+++ b/src/librustc_mir/dataflow/impls/borrowed_locals.rs
@@ -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<'_> {