about summary refs log tree commit diff
path: root/src/librustc
diff options
context:
space:
mode:
authorDylan MacKenzie <ecstaticmorse@gmail.com>2019-08-29 13:22:16 -0700
committerDylan MacKenzie <ecstaticmorse@gmail.com>2019-08-29 13:40:28 -0700
commit86487329bb385f74bed67718f2358436ddca1aa4 (patch)
tree7c12cc5ecf7a9865e35fa65a7bf7a89be2264edf /src/librustc
parent555d7a2fd6165b614cfc01136d8e3f5c465a1582 (diff)
downloadrust-86487329bb385f74bed67718f2358436ddca1aa4.tar.gz
rust-86487329bb385f74bed67718f2358436ddca1aa4.zip
Add `Place::is_indirect`
This returns whether a `Place` references the same region of memory
as its base, or equivalently whether it contains a `Deref` projection.

This is helpful for analyses that must track state for locals, since an
assignment to `x` or `x.field` is fundamentally different than one to
`*x`, which may mutate any memory region.
Diffstat (limited to 'src/librustc')
-rw-r--r--src/librustc/mir/mod.rs25
1 files changed, 25 insertions, 0 deletions
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 858b77af804..a07f12cd9c5 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -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>>;
@@ -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.
     //