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.
This commit is contained in:
Dylan MacKenzie 2019-08-29 13:22:16 -07:00
parent 555d7a2fd6
commit 86487329bb

View File

@ -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.
//