1
Fork 0

Make HasTop and HasBottom consts.

This commit is contained in:
Camille GILLOT 2023-04-24 17:10:39 +00:00
parent f7b831ac8a
commit 71138e9933
3 changed files with 24 additions and 34 deletions

View file

@ -75,12 +75,12 @@ pub trait MeetSemiLattice: Eq {
/// A set that has a "bottom" element, which is less than or equal to any other element. /// A set that has a "bottom" element, which is less than or equal to any other element.
pub trait HasBottom { pub trait HasBottom {
fn bottom() -> Self; const BOTTOM: Self;
} }
/// A set that has a "top" element, which is greater than or equal to any other element. /// A set that has a "top" element, which is greater than or equal to any other element.
pub trait HasTop { pub trait HasTop {
fn top() -> Self; const TOP: Self;
} }
/// A `bool` is a "two-point" lattice with `true` as the top element and `false` as the bottom: /// A `bool` is a "two-point" lattice with `true` as the top element and `false` as the bottom:
@ -113,15 +113,11 @@ impl MeetSemiLattice for bool {
} }
impl HasBottom for bool { impl HasBottom for bool {
fn bottom() -> Self { const BOTTOM: Self = false;
false
}
} }
impl HasTop for bool { impl HasTop for bool {
fn top() -> Self { const TOP: Self = true;
true
}
} }
/// A tuple (or list) of lattices is itself a lattice whose least upper bound is the concatenation /// A tuple (or list) of lattices is itself a lattice whose least upper bound is the concatenation
@ -274,13 +270,9 @@ impl<T: Clone + Eq> MeetSemiLattice for FlatSet<T> {
} }
impl<T> HasBottom for FlatSet<T> { impl<T> HasBottom for FlatSet<T> {
fn bottom() -> Self { const BOTTOM: Self = Self::Bottom;
Self::Bottom
}
} }
impl<T> HasTop for FlatSet<T> { impl<T> HasTop for FlatSet<T> {
fn top() -> Self { const TOP: Self = Self::Top;
Self::Top
}
} }

View file

@ -74,11 +74,11 @@ pub trait ValueAnalysis<'tcx> {
StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
// StorageLive leaves the local in an uninitialized state. // StorageLive leaves the local in an uninitialized state.
// StorageDead makes it UB to access the local afterwards. // StorageDead makes it UB to access the local afterwards.
state.flood_with(Place::from(*local).as_ref(), self.map(), Self::Value::bottom()); state.flood_with(Place::from(*local).as_ref(), self.map(), Self::Value::BOTTOM);
} }
StatementKind::Deinit(box place) => { StatementKind::Deinit(box place) => {
// Deinit makes the place uninitialized. // Deinit makes the place uninitialized.
state.flood_with(place.as_ref(), self.map(), Self::Value::bottom()); state.flood_with(place.as_ref(), self.map(), Self::Value::BOTTOM);
} }
StatementKind::Retag(..) => { StatementKind::Retag(..) => {
// We don't track references. // We don't track references.
@ -154,7 +154,7 @@ pub trait ValueAnalysis<'tcx> {
Rvalue::CopyForDeref(place) => self.handle_operand(&Operand::Copy(*place), state), Rvalue::CopyForDeref(place) => self.handle_operand(&Operand::Copy(*place), state),
Rvalue::Ref(..) | Rvalue::AddressOf(..) => { Rvalue::Ref(..) | Rvalue::AddressOf(..) => {
// We don't track such places. // We don't track such places.
ValueOrPlace::top() ValueOrPlace::TOP
} }
Rvalue::Repeat(..) Rvalue::Repeat(..)
| Rvalue::ThreadLocalRef(..) | Rvalue::ThreadLocalRef(..)
@ -168,7 +168,7 @@ pub trait ValueAnalysis<'tcx> {
| Rvalue::Aggregate(..) | Rvalue::Aggregate(..)
| Rvalue::ShallowInitBox(..) => { | Rvalue::ShallowInitBox(..) => {
// No modification is possible through these r-values. // No modification is possible through these r-values.
ValueOrPlace::top() ValueOrPlace::TOP
} }
} }
} }
@ -196,7 +196,7 @@ pub trait ValueAnalysis<'tcx> {
self.map() self.map()
.find(place.as_ref()) .find(place.as_ref())
.map(ValueOrPlace::Place) .map(ValueOrPlace::Place)
.unwrap_or(ValueOrPlace::top()) .unwrap_or(ValueOrPlace::TOP)
} }
} }
} }
@ -214,7 +214,7 @@ pub trait ValueAnalysis<'tcx> {
_constant: &Constant<'tcx>, _constant: &Constant<'tcx>,
_state: &mut State<Self::Value>, _state: &mut State<Self::Value>,
) -> Self::Value { ) -> Self::Value {
Self::Value::top() Self::Value::TOP
} }
/// The effect of a successful function call return should not be /// The effect of a successful function call return should not be
@ -229,7 +229,7 @@ pub trait ValueAnalysis<'tcx> {
// Effect is applied by `handle_call_return`. // Effect is applied by `handle_call_return`.
} }
TerminatorKind::Drop { place, .. } => { TerminatorKind::Drop { place, .. } => {
state.flood_with(place.as_ref(), self.map(), Self::Value::bottom()); state.flood_with(place.as_ref(), self.map(), Self::Value::BOTTOM);
} }
TerminatorKind::Yield { .. } => { TerminatorKind::Yield { .. } => {
// They would have an effect, but are not allowed in this phase. // They would have an effect, but are not allowed in this phase.
@ -307,7 +307,7 @@ impl<'tcx, T: ValueAnalysis<'tcx>> AnalysisDomain<'tcx> for ValueAnalysisWrapper
fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) { fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
// The initial state maps all tracked places of argument projections to and the rest to ⊥. // The initial state maps all tracked places of argument projections to and the rest to ⊥.
assert!(matches!(state.0, StateData::Unreachable)); assert!(matches!(state.0, StateData::Unreachable));
let values = IndexVec::from_elem_n(T::Value::bottom(), self.0.map().value_count); let values = IndexVec::from_elem_n(T::Value::BOTTOM, self.0.map().value_count);
*state = State(StateData::Reachable(values)); *state = State(StateData::Reachable(values));
for arg in body.args_iter() { for arg in body.args_iter() {
state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map()); state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map());
@ -437,7 +437,7 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
} }
pub fn flood_all(&mut self) { pub fn flood_all(&mut self) {
self.flood_all_with(V::top()) self.flood_all_with(V::TOP)
} }
pub fn flood_all_with(&mut self, value: V) { pub fn flood_all_with(&mut self, value: V) {
@ -455,7 +455,7 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
} }
pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map) { pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map) {
self.flood_with(place, map, V::top()) self.flood_with(place, map, V::TOP)
} }
pub fn flood_discr_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) { pub fn flood_discr_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) {
@ -468,7 +468,7 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
} }
pub fn flood_discr(&mut self, place: PlaceRef<'_>, map: &Map) { pub fn flood_discr(&mut self, place: PlaceRef<'_>, map: &Map) {
self.flood_discr_with(place, map, V::top()) self.flood_discr_with(place, map, V::TOP)
} }
/// Low-level method that assigns to a place. /// Low-level method that assigns to a place.
@ -538,14 +538,14 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
/// Retrieve the value stored for a place, or if it is not tracked. /// Retrieve the value stored for a place, or if it is not tracked.
pub fn get(&self, place: PlaceRef<'_>, map: &Map) -> V { pub fn get(&self, place: PlaceRef<'_>, map: &Map) -> V {
map.find(place).map(|place| self.get_idx(place, map)).unwrap_or(V::top()) map.find(place).map(|place| self.get_idx(place, map)).unwrap_or(V::TOP)
} }
/// Retrieve the value stored for a place, or if it is not tracked. /// Retrieve the value stored for a place, or if it is not tracked.
pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map) -> V { pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map) -> V {
match map.find_discr(place) { match map.find_discr(place) {
Some(place) => self.get_idx(place, map), Some(place) => self.get_idx(place, map),
None => V::top(), None => V::TOP,
} }
} }
@ -553,11 +553,11 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V { pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V {
match &self.0 { match &self.0 {
StateData::Reachable(values) => { StateData::Reachable(values) => {
map.places[place].value_index.map(|v| values[v].clone()).unwrap_or(V::top()) map.places[place].value_index.map(|v| values[v].clone()).unwrap_or(V::TOP)
} }
StateData::Unreachable => { StateData::Unreachable => {
// Because this is unreachable, we can return any value we want. // Because this is unreachable, we can return any value we want.
V::bottom() V::BOTTOM
} }
} }
} }
@ -909,9 +909,7 @@ pub enum ValueOrPlace<V> {
} }
impl<V: HasTop> ValueOrPlace<V> { impl<V: HasTop> ValueOrPlace<V> {
pub fn top() -> Self { pub const TOP: Self = ValueOrPlace::Value(V::TOP);
ValueOrPlace::Value(V::top())
}
} }
/// The set of projection elements that can be used by a tracked place. /// The set of projection elements that can be used by a tracked place.

View file

@ -208,8 +208,8 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
_ => unreachable!(), _ => unreachable!(),
} }
.map(|result| ValueOrPlace::Value(self.wrap_immediate(result, *ty))) .map(|result| ValueOrPlace::Value(self.wrap_immediate(result, *ty)))
.unwrap_or(ValueOrPlace::top()), .unwrap_or(ValueOrPlace::TOP),
_ => ValueOrPlace::top(), _ => ValueOrPlace::TOP,
}, },
Rvalue::BinaryOp(op, box (left, right)) => { Rvalue::BinaryOp(op, box (left, right)) => {
// Overflows must be ignored here. // Overflows must be ignored here.