Rollup merge of #133938 - nnethercote:rustc_mir_dataflow-renamings, r=oli-obk

`rustc_mir_dataflow` cleanups, including some renamings

Some opinionated commits in this collection, let's see how we go.

r? `@cjgillot`
This commit is contained in:
Matthias Krüger 2024-12-13 17:25:29 +01:00 committed by GitHub
commit c6ebe6fe3b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 362 additions and 424 deletions

View file

@ -179,15 +179,15 @@ where
/// Advances the cursor to hold the dataflow state at `target` before its "primary" effect is
/// applied.
///
/// The "before" effect at the target location *will be* applied.
/// The "early" effect at the target location *will be* applied.
pub fn seek_before_primary_effect(&mut self, target: Location) {
self.seek_after(target, Effect::Before)
self.seek_after(target, Effect::Early)
}
/// Advances the cursor to hold the dataflow state at `target` after its "primary" effect is
/// applied.
///
/// The "before" effect at the target location will be applied as well.
/// The "early" effect at the target location will be applied as well.
pub fn seek_after_primary_effect(&mut self, target: Location) {
self.seek_after(target, Effect::Primary)
}
@ -222,12 +222,12 @@ where
#[rustfmt::skip]
let next_effect = if A::Direction::IS_FORWARD {
self.pos.curr_effect_index.map_or_else(
|| Effect::Before.at_index(0),
|| Effect::Early.at_index(0),
EffectIndex::next_in_forward_order,
)
} else {
self.pos.curr_effect_index.map_or_else(
|| Effect::Before.at_index(block_data.statements.len()),
|| Effect::Early.at_index(block_data.statements.len()),
EffectIndex::next_in_backward_order,
)
};

View file

@ -66,12 +66,12 @@ impl Direction for Backward {
{
let terminator = block_data.terminator();
let location = Location { block, statement_index: block_data.statements.len() };
analysis.apply_before_terminator_effect(state, terminator, location);
analysis.apply_terminator_effect(state, terminator, location);
analysis.apply_early_terminator_effect(state, terminator, location);
analysis.apply_primary_terminator_effect(state, terminator, location);
for (statement_index, statement) in block_data.statements.iter().enumerate().rev() {
let location = Location { block, statement_index };
analysis.apply_before_statement_effect(state, statement, location);
analysis.apply_statement_effect(state, statement, location);
analysis.apply_early_statement_effect(state, statement, location);
analysis.apply_primary_statement_effect(state, statement, location);
}
let exit_state = state;
@ -159,14 +159,14 @@ impl Direction for Backward {
let location = Location { block, statement_index: from.statement_index };
let terminator = block_data.terminator();
if from.effect == Effect::Before {
analysis.apply_before_terminator_effect(state, terminator, location);
if to == Effect::Before.at_index(terminator_index) {
if from.effect == Effect::Early {
analysis.apply_early_terminator_effect(state, terminator, location);
if to == Effect::Early.at_index(terminator_index) {
return;
}
}
analysis.apply_terminator_effect(state, terminator, location);
analysis.apply_primary_terminator_effect(state, terminator, location);
if to == Effect::Primary.at_index(terminator_index) {
return;
}
@ -180,7 +180,7 @@ impl Direction for Backward {
let location = Location { block, statement_index: from.statement_index };
let statement = &block_data.statements[from.statement_index];
analysis.apply_statement_effect(state, statement, location);
analysis.apply_primary_statement_effect(state, statement, location);
if to == Effect::Primary.at_index(from.statement_index) {
return;
}
@ -188,7 +188,7 @@ impl Direction for Backward {
from.statement_index - 1
}
Effect::Before => from.statement_index,
Effect::Early => from.statement_index,
};
// Handle all statements between `first_unapplied_idx` and `to.statement_index`.
@ -196,21 +196,21 @@ impl Direction for Backward {
for statement_index in (to.statement_index..next_effect).rev().map(|i| i + 1) {
let location = Location { block, statement_index };
let statement = &block_data.statements[statement_index];
analysis.apply_before_statement_effect(state, statement, location);
analysis.apply_statement_effect(state, statement, location);
analysis.apply_early_statement_effect(state, statement, location);
analysis.apply_primary_statement_effect(state, statement, location);
}
// Handle the statement at `to`.
let location = Location { block, statement_index: to.statement_index };
let statement = &block_data.statements[to.statement_index];
analysis.apply_before_statement_effect(state, statement, location);
analysis.apply_early_statement_effect(state, statement, location);
if to.effect == Effect::Before {
if to.effect == Effect::Early {
return;
}
analysis.apply_statement_effect(state, statement, location);
analysis.apply_primary_statement_effect(state, statement, location);
}
fn visit_results_in_block<'mir, 'tcx, A>(
@ -228,17 +228,17 @@ impl Direction for Backward {
let loc = Location { block, statement_index: block_data.statements.len() };
let term = block_data.terminator();
results.analysis.apply_before_terminator_effect(state, term, loc);
vis.visit_terminator_before_primary_effect(results, state, term, loc);
results.analysis.apply_terminator_effect(state, term, loc);
vis.visit_terminator_after_primary_effect(results, state, term, loc);
results.analysis.apply_early_terminator_effect(state, term, loc);
vis.visit_after_early_terminator_effect(results, state, term, loc);
results.analysis.apply_primary_terminator_effect(state, term, loc);
vis.visit_after_primary_terminator_effect(results, state, term, loc);
for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
let loc = Location { block, statement_index };
results.analysis.apply_before_statement_effect(state, stmt, loc);
vis.visit_statement_before_primary_effect(results, state, stmt, loc);
results.analysis.apply_statement_effect(state, stmt, loc);
vis.visit_statement_after_primary_effect(results, state, stmt, loc);
results.analysis.apply_early_statement_effect(state, stmt, loc);
vis.visit_after_early_statement_effect(results, state, stmt, loc);
results.analysis.apply_primary_statement_effect(state, stmt, loc);
vis.visit_after_primary_statement_effect(results, state, stmt, loc);
}
vis.visit_block_start(state);
@ -294,13 +294,13 @@ impl Direction for Forward {
{
for (statement_index, statement) in block_data.statements.iter().enumerate() {
let location = Location { block, statement_index };
analysis.apply_before_statement_effect(state, statement, location);
analysis.apply_statement_effect(state, statement, location);
analysis.apply_early_statement_effect(state, statement, location);
analysis.apply_primary_statement_effect(state, statement, location);
}
let terminator = block_data.terminator();
let location = Location { block, statement_index: block_data.statements.len() };
analysis.apply_before_terminator_effect(state, terminator, location);
let edges = analysis.apply_terminator_effect(state, terminator, location);
analysis.apply_early_terminator_effect(state, terminator, location);
let edges = analysis.apply_primary_terminator_effect(state, terminator, location);
let exit_state = state;
match edges {
@ -368,21 +368,21 @@ impl Direction for Forward {
// after effect, do so now and start the loop below from the next statement.
let first_unapplied_index = match from.effect {
Effect::Before => from.statement_index,
Effect::Early => from.statement_index,
Effect::Primary if from.statement_index == terminator_index => {
debug_assert_eq!(from, to);
let location = Location { block, statement_index: terminator_index };
let terminator = block_data.terminator();
analysis.apply_terminator_effect(state, terminator, location);
analysis.apply_primary_terminator_effect(state, terminator, location);
return;
}
Effect::Primary => {
let location = Location { block, statement_index: from.statement_index };
let statement = &block_data.statements[from.statement_index];
analysis.apply_statement_effect(state, statement, location);
analysis.apply_primary_statement_effect(state, statement, location);
// If we only needed to apply the after effect of the statement at `idx`, we are
// done.
@ -399,8 +399,8 @@ impl Direction for Forward {
for statement_index in first_unapplied_index..to.statement_index {
let location = Location { block, statement_index };
let statement = &block_data.statements[statement_index];
analysis.apply_before_statement_effect(state, statement, location);
analysis.apply_statement_effect(state, statement, location);
analysis.apply_early_statement_effect(state, statement, location);
analysis.apply_primary_statement_effect(state, statement, location);
}
// Handle the statement or terminator at `to`.
@ -408,17 +408,17 @@ impl Direction for Forward {
let location = Location { block, statement_index: to.statement_index };
if to.statement_index == terminator_index {
let terminator = block_data.terminator();
analysis.apply_before_terminator_effect(state, terminator, location);
analysis.apply_early_terminator_effect(state, terminator, location);
if to.effect == Effect::Primary {
analysis.apply_terminator_effect(state, terminator, location);
analysis.apply_primary_terminator_effect(state, terminator, location);
}
} else {
let statement = &block_data.statements[to.statement_index];
analysis.apply_before_statement_effect(state, statement, location);
analysis.apply_early_statement_effect(state, statement, location);
if to.effect == Effect::Primary {
analysis.apply_statement_effect(state, statement, location);
analysis.apply_primary_statement_effect(state, statement, location);
}
}
}
@ -438,18 +438,18 @@ impl Direction for Forward {
for (statement_index, stmt) in block_data.statements.iter().enumerate() {
let loc = Location { block, statement_index };
results.analysis.apply_before_statement_effect(state, stmt, loc);
vis.visit_statement_before_primary_effect(results, state, stmt, loc);
results.analysis.apply_statement_effect(state, stmt, loc);
vis.visit_statement_after_primary_effect(results, state, stmt, loc);
results.analysis.apply_early_statement_effect(state, stmt, loc);
vis.visit_after_early_statement_effect(results, state, stmt, loc);
results.analysis.apply_primary_statement_effect(state, stmt, loc);
vis.visit_after_primary_statement_effect(results, state, stmt, loc);
}
let loc = Location { block, statement_index: block_data.statements.len() };
let term = block_data.terminator();
results.analysis.apply_before_terminator_effect(state, term, loc);
vis.visit_terminator_before_primary_effect(results, state, term, loc);
results.analysis.apply_terminator_effect(state, term, loc);
vis.visit_terminator_after_primary_effect(results, state, term, loc);
results.analysis.apply_early_terminator_effect(state, term, loc);
vis.visit_after_early_terminator_effect(results, state, term, loc);
results.analysis.apply_primary_terminator_effect(state, term, loc);
vis.visit_after_primary_terminator_effect(results, state, term, loc);
vis.visit_block_end(state);
}

View file

@ -724,7 +724,7 @@ where
}
}
fn visit_statement_before_primary_effect(
fn visit_after_early_statement_effect(
&mut self,
results: &mut Results<'tcx, A>,
state: &A::Domain,
@ -737,7 +737,7 @@ where
}
}
fn visit_statement_after_primary_effect(
fn visit_after_primary_statement_effect(
&mut self,
results: &mut Results<'tcx, A>,
state: &A::Domain,
@ -748,7 +748,7 @@ where
self.prev_state.clone_from(state)
}
fn visit_terminator_before_primary_effect(
fn visit_after_early_terminator_effect(
&mut self,
results: &mut Results<'tcx, A>,
state: &A::Domain,
@ -761,7 +761,7 @@ where
}
}
fn visit_terminator_after_primary_effect(
fn visit_after_primary_terminator_effect(
&mut self,
results: &mut Results<'tcx, A>,
state: &A::Domain,

View file

@ -38,10 +38,8 @@
//! [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram
//! [poset]: https://en.wikipedia.org/wiki/Partially_ordered_set
use std::iter;
use rustc_index::Idx;
use rustc_index::bit_set::{BitSet, MixedBitSet};
use rustc_index::{Idx, IndexVec};
use crate::framework::BitSetExt;
@ -70,53 +68,6 @@ pub trait HasTop {
const TOP: Self;
}
/// A `bool` is a "two-point" lattice with `true` as the top element and `false` as the bottom:
///
/// ```text
/// true
/// |
/// false
/// ```
impl JoinSemiLattice for bool {
fn join(&mut self, other: &Self) -> bool {
if let (false, true) = (*self, *other) {
*self = true;
return true;
}
false
}
}
impl HasBottom for bool {
const BOTTOM: Self = false;
fn is_bottom(&self) -> bool {
!self
}
}
impl HasTop for bool {
const TOP: Self = true;
}
/// A tuple (or list) of lattices is itself a lattice whose least upper bound is the concatenation
/// of the least upper bounds of each element of the tuple (or list).
///
/// In other words:
/// (A₀, A₁, ..., Aₙ) (B₀, B₁, ..., Bₙ) = (A₀B₀, A₁B₁, ..., AₙBₙ)
impl<I: Idx, T: JoinSemiLattice> JoinSemiLattice for IndexVec<I, T> {
fn join(&mut self, other: &Self) -> bool {
assert_eq!(self.len(), other.len());
let mut changed = false;
for (a, b) in iter::zip(self, other) {
changed |= a.join(b);
}
changed
}
}
/// A `BitSet` represents the lattice formed by the powerset of all possible values of
/// the index type `T` ordered by inclusion. Equivalently, it is a tuple of "two-point" lattices,
/// one for each possible value of `T`.
@ -197,18 +148,6 @@ impl<T> MaybeReachable<T> {
}
}
impl<T> HasBottom for MaybeReachable<T> {
const BOTTOM: Self = MaybeReachable::Unreachable;
fn is_bottom(&self) -> bool {
matches!(self, Self::Unreachable)
}
}
impl<T: HasTop> HasTop for MaybeReachable<T> {
const TOP: Self = MaybeReachable::Reachable(T::TOP);
}
impl<S> MaybeReachable<S> {
/// Return whether the current state contains the given element. If the state is unreachable,
/// it does no contain anything.

View file

@ -56,7 +56,7 @@ mod visitor;
pub use self::cursor::ResultsCursor;
pub use self::direction::{Backward, Direction, Forward};
pub use self::lattice::{JoinSemiLattice, MaybeReachable};
pub use self::results::{EntrySets, Results};
pub use self::results::{EntryStates, Results};
pub use self::visitor::{ResultsVisitor, visit_results};
/// Analysis domains are all bitsets of various kinds. This trait holds
@ -122,8 +122,23 @@ pub trait Analysis<'tcx> {
// `resume`). It's not obvious how to handle `yield` points in coroutines, however.
fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain);
/// Updates the current dataflow state with an "early" effect, i.e. one
/// that occurs immediately before the given statement.
///
/// This method is useful if the consumer of the results of this analysis only needs to observe
/// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule,
/// analyses should not implement this without also implementing
/// `apply_primary_statement_effect`.
fn apply_early_statement_effect(
&mut self,
_state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>,
_location: Location,
) {
}
/// Updates the current dataflow state with the effect of evaluating a statement.
fn apply_statement_effect(
fn apply_primary_statement_effect(
&mut self,
state: &mut Self::Domain,
statement: &mir::Statement<'tcx>,
@ -131,15 +146,16 @@ pub trait Analysis<'tcx> {
);
/// Updates the current dataflow state with an effect that occurs immediately *before* the
/// given statement.
/// given terminator.
///
/// This method is useful if the consumer of the results of this analysis only needs to observe
/// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule,
/// analyses should not implement this without also implementing `apply_statement_effect`.
fn apply_before_statement_effect(
/// This method is useful if the consumer of the results of this analysis needs only to observe
/// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule,
/// analyses should not implement this without also implementing
/// `apply_primary_terminator_effect`.
fn apply_early_terminator_effect(
&mut self,
_state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>,
_terminator: &mir::Terminator<'tcx>,
_location: Location,
) {
}
@ -150,7 +166,7 @@ pub trait Analysis<'tcx> {
/// in this function. That should go in `apply_call_return_effect`. For example, in the
/// `InitializedPlaces` analyses, the return place for a function call is not marked as
/// initialized here.
fn apply_terminator_effect<'mir>(
fn apply_primary_terminator_effect<'mir>(
&mut self,
_state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>,
@ -159,27 +175,13 @@ pub trait Analysis<'tcx> {
terminator.edges()
}
/// Updates the current dataflow state with an effect that occurs immediately *before* the
/// given terminator.
///
/// This method is useful if the consumer of the results of this analysis needs only to observe
/// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule,
/// analyses should not implement this without also implementing `apply_terminator_effect`.
fn apply_before_terminator_effect(
&mut self,
_state: &mut Self::Domain,
_terminator: &mir::Terminator<'tcx>,
_location: Location,
) {
}
/* Edge-specific effects */
/// Updates the current dataflow state with the effect of a successful return from a `Call`
/// terminator.
///
/// This is separate from `apply_terminator_effect` to properly track state across unwind
/// edges.
/// This is separate from `apply_primary_terminator_effect` to properly track state across
/// unwind edges.
fn apply_call_return_effect(
&mut self,
_state: &mut Self::Domain,
@ -234,11 +236,12 @@ pub trait Analysis<'tcx> {
Self: Sized,
Self::Domain: DebugWithContext<Self>,
{
let mut entry_sets =
let mut entry_states =
IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len());
self.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);
self.initialize_start_block(body, &mut entry_states[mir::START_BLOCK]);
if Self::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != self.bottom_value(body) {
if Self::Direction::IS_BACKWARD && entry_states[mir::START_BLOCK] != self.bottom_value(body)
{
bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
}
@ -262,9 +265,9 @@ pub trait Analysis<'tcx> {
let mut state = self.bottom_value(body);
while let Some(bb) = dirty_queue.pop() {
// Set the state to the entry state of the block.
// This is equivalent to `state = entry_sets[bb].clone()`,
// This is equivalent to `state = entry_states[bb].clone()`,
// but it saves an allocation, thus improving compile times.
state.clone_from(&entry_sets[bb]);
state.clone_from(&entry_states[bb]);
Self::Direction::apply_effects_in_block(
&mut self,
@ -273,7 +276,7 @@ pub trait Analysis<'tcx> {
bb,
&body[bb],
|target: BasicBlock, state: &Self::Domain| {
let set_changed = entry_sets[target].join(state);
let set_changed = entry_states[target].join(state);
if set_changed {
dirty_queue.insert(target);
}
@ -281,7 +284,7 @@ pub trait Analysis<'tcx> {
);
}
let mut results = Results { analysis: self, entry_sets };
let mut results = Results { analysis: self, entry_states };
if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
let res = write_graphviz_results(tcx, body, &mut results, pass_name);
@ -358,11 +361,10 @@ impl<T, S: GenKill<T>> GenKill<T> for MaybeReachable<S> {
// NOTE: DO NOT CHANGE VARIANT ORDER. The derived `Ord` impls rely on the current order.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Effect {
/// The "before" effect (e.g., `apply_before_statement_effect`) for a statement (or
/// terminator).
Before,
/// The "early" effect (e.g., `apply_early_statement_effect`) for a statement/terminator.
Early,
/// The "primary" effect (e.g., `apply_statement_effect`) for a statement (or terminator).
/// The "primary" effect (e.g., `apply_primary_statement_effect`) for a statement/terminator.
Primary,
}
@ -381,15 +383,15 @@ pub struct EffectIndex {
impl EffectIndex {
fn next_in_forward_order(self) -> Self {
match self.effect {
Effect::Before => Effect::Primary.at_index(self.statement_index),
Effect::Primary => Effect::Before.at_index(self.statement_index + 1),
Effect::Early => Effect::Primary.at_index(self.statement_index),
Effect::Primary => Effect::Early.at_index(self.statement_index + 1),
}
}
fn next_in_backward_order(self) -> Self {
match self.effect {
Effect::Before => Effect::Primary.at_index(self.statement_index),
Effect::Primary => Effect::Before.at_index(self.statement_index - 1),
Effect::Early => Effect::Primary.at_index(self.statement_index),
Effect::Primary => Effect::Early.at_index(self.statement_index - 1),
}
}

View file

@ -6,7 +6,7 @@ use rustc_middle::mir::{BasicBlock, Body, traversal};
use super::{Analysis, ResultsCursor, ResultsVisitor, visit_results};
use crate::framework::cursor::ResultsHandle;
pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
pub type EntryStates<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
/// A dataflow analysis that has converged to fixpoint. It only holds the domain values at the
/// entry of each basic block. Domain values in other parts of the block are recomputed on the fly
@ -17,7 +17,7 @@ where
A: Analysis<'tcx>,
{
pub analysis: A,
pub entry_sets: EntrySets<'tcx, A>,
pub entry_states: EntryStates<'tcx, A>,
}
impl<'tcx, A> Results<'tcx, A>
@ -40,7 +40,7 @@ where
/// Gets the dataflow state for the given block.
pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain {
&self.entry_sets[block]
&self.entry_states[block]
}
pub fn visit_with<'mir>(

View file

@ -73,7 +73,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> {
///
/// The `102` in the block's entry set is derived from the basic block index and ensures that the
/// expected state is unique across all basic blocks. Remember, it is generated by
/// `mock_entry_sets`, not from actually running `MockAnalysis` to fixpoint.
/// `mock_entry_states`, not from actually running `MockAnalysis` to fixpoint.
struct MockAnalysis<'tcx, D> {
body: &'tcx mir::Body<'tcx>,
dir: PhantomData<D>,
@ -90,7 +90,7 @@ impl<D: Direction> MockAnalysis<'_, D> {
ret
}
fn mock_entry_sets(&self) -> IndexVec<BasicBlock, BitSet<usize>> {
fn mock_entry_states(&self) -> IndexVec<BasicBlock, BitSet<usize>> {
let empty = self.bottom_value(self.body);
let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks);
@ -104,7 +104,7 @@ impl<D: Direction> MockAnalysis<'_, D> {
/// Returns the index that should be added to the dataflow state at the given target.
fn effect(&self, loc: EffectIndex) -> usize {
let idx = match loc.effect {
Effect::Before => loc.statement_index * 2,
Effect::Early => loc.statement_index * 2,
Effect::Primary => loc.statement_index * 2 + 1,
};
@ -128,14 +128,14 @@ impl<D: Direction> MockAnalysis<'_, D> {
let target = match target {
SeekTarget::BlockEntry { .. } => return ret,
SeekTarget::Before(loc) => Effect::Before.at_index(loc.statement_index),
SeekTarget::Early(loc) => Effect::Early.at_index(loc.statement_index),
SeekTarget::After(loc) => Effect::Primary.at_index(loc.statement_index),
};
let mut pos = if D::IS_FORWARD {
Effect::Before.at_index(0)
Effect::Early.at_index(0)
} else {
Effect::Before.at_index(self.body[block].statements.len())
Effect::Early.at_index(self.body[block].statements.len())
};
loop {
@ -168,7 +168,17 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
unimplemented!("This is never called since `MockAnalysis` is never iterated to fixpoint");
}
fn apply_statement_effect(
fn apply_early_statement_effect(
&mut self,
state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>,
location: Location,
) {
let idx = self.effect(Effect::Early.at_index(location.statement_index));
assert!(state.insert(idx));
}
fn apply_primary_statement_effect(
&mut self,
state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>,
@ -178,17 +188,17 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
assert!(state.insert(idx));
}
fn apply_before_statement_effect(
fn apply_early_terminator_effect(
&mut self,
state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>,
_terminator: &mir::Terminator<'tcx>,
location: Location,
) {
let idx = self.effect(Effect::Before.at_index(location.statement_index));
let idx = self.effect(Effect::Early.at_index(location.statement_index));
assert!(state.insert(idx));
}
fn apply_terminator_effect<'mir>(
fn apply_primary_terminator_effect<'mir>(
&mut self,
state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>,
@ -198,22 +208,12 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
assert!(state.insert(idx));
terminator.edges()
}
fn apply_before_terminator_effect(
&mut self,
state: &mut Self::Domain,
_terminator: &mir::Terminator<'tcx>,
location: Location,
) {
let idx = self.effect(Effect::Before.at_index(location.statement_index));
assert!(state.insert(idx));
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum SeekTarget {
BlockEntry(BasicBlock),
Before(Location),
Early(Location),
After(Location),
}
@ -223,7 +223,7 @@ impl SeekTarget {
match *self {
BlockEntry(block) => block,
Before(loc) | After(loc) => loc.block,
Early(loc) | After(loc) => loc.block,
}
}
@ -235,7 +235,7 @@ impl SeekTarget {
.map(move |(i, kind)| {
let loc = Location { block, statement_index: i };
match kind {
0 => SeekTarget::Before(loc),
0 => SeekTarget::Early(loc),
1 => SeekTarget::After(loc),
_ => unreachable!(),
}
@ -249,7 +249,7 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
let body = analysis.body;
let mut cursor =
Results { entry_sets: analysis.mock_entry_sets(), analysis }.into_results_cursor(body);
Results { entry_states: analysis.mock_entry_states(), analysis }.into_results_cursor(body);
cursor.allow_unreachable();
@ -262,7 +262,7 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
match targ {
BlockEntry(block) => cursor.seek_to_block_entry(block),
Before(loc) => cursor.seek_before_primary_effect(loc),
Early(loc) => cursor.seek_before_primary_effect(loc),
After(loc) => cursor.seek_after_primary_effect(loc),
}

View file

@ -35,9 +35,9 @@ where
{
fn visit_block_start(&mut self, _state: &A::Domain) {}
/// Called with the `before_statement_effect` of the given statement applied to `state` but not
/// its `statement_effect`.
fn visit_statement_before_primary_effect(
/// // njn: grep for "before", "primary", etc.
/// Called after the "early" effect of the given statement is applied to `state`.
fn visit_after_early_statement_effect(
&mut self,
_results: &mut Results<'tcx, A>,
_state: &A::Domain,
@ -46,9 +46,8 @@ where
) {
}
/// Called with both the `before_statement_effect` and the `statement_effect` of the given
/// statement applied to `state`.
fn visit_statement_after_primary_effect(
/// Called after the "primary" effect of the given statement is applied to `state`.
fn visit_after_primary_statement_effect(
&mut self,
_results: &mut Results<'tcx, A>,
_state: &A::Domain,
@ -57,9 +56,8 @@ where
) {
}
/// Called with the `before_terminator_effect` of the given terminator applied to `state` but
/// not its `terminator_effect`.
fn visit_terminator_before_primary_effect(
/// Called after the "early" effect of the given terminator is applied to `state`.
fn visit_after_early_terminator_effect(
&mut self,
_results: &mut Results<'tcx, A>,
_state: &A::Domain,
@ -68,11 +66,10 @@ where
) {
}
/// Called with both the `before_terminator_effect` and the `terminator_effect` of the given
/// terminator applied to `state`.
/// Called after the "primary" effect of the given terminator is applied to `state`.
///
/// The `call_return_effect` (if one exists) will *not* be applied to `state`.
fn visit_terminator_after_primary_effect(
fn visit_after_primary_terminator_effect(
&mut self,
_results: &mut Results<'tcx, A>,
_state: &A::Domain,

View file

@ -33,22 +33,22 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals {
// No locals are aliased on function entry
}
fn apply_statement_effect(
fn apply_primary_statement_effect(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
statement: &Statement<'tcx>,
location: Location,
) {
Self::transfer_function(trans).visit_statement(statement, location);
Self::transfer_function(state).visit_statement(statement, location);
}
fn apply_terminator_effect<'mir>(
fn apply_primary_terminator_effect<'mir>(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
terminator: &'mir Terminator<'tcx>,
location: Location,
) -> TerminatorEdges<'mir, 'tcx> {
Self::transfer_function(trans).visit_terminator(terminator, location);
Self::transfer_function(state).visit_terminator(terminator, location);
terminator.edges()
}
}

View file

@ -70,7 +70,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
pub fn is_unwind_dead(
&self,
place: mir::Place<'tcx>,
state: &MaybeReachable<MixedBitSet<MovePathIndex>>,
state: &<Self as Analysis<'tcx>>::Domain,
) -> bool {
if let LookupResult::Exact(path) = self.move_data().rev_lookup.find(place.as_ref()) {
let mut maybe_live = false;
@ -218,26 +218,26 @@ impl<'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'_, 'tcx> {
impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
fn update_bits(
trans: &mut <Self as Analysis<'tcx>>::Domain,
state: &mut <Self as Analysis<'tcx>>::Domain,
path: MovePathIndex,
state: DropFlagState,
dfstate: DropFlagState,
) {
match state {
DropFlagState::Absent => trans.kill(path),
DropFlagState::Present => trans.gen_(path),
match dfstate {
DropFlagState::Absent => state.kill(path),
DropFlagState::Present => state.gen_(path),
}
}
}
impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> {
fn update_bits(
trans: &mut <Self as Analysis<'tcx>>::Domain,
state: &mut <Self as Analysis<'tcx>>::Domain,
path: MovePathIndex,
state: DropFlagState,
dfstate: DropFlagState,
) {
match state {
DropFlagState::Absent => trans.gen_(path),
DropFlagState::Present => trans.kill(path),
match dfstate {
DropFlagState::Absent => state.gen_(path),
DropFlagState::Present => state.kill(path),
}
}
}
@ -263,14 +263,14 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
});
}
fn apply_statement_effect(
fn apply_primary_statement_effect(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
statement: &mir::Statement<'tcx>,
location: Location,
) {
drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
Self::update_bits(trans, path, s)
Self::update_bits(state, path, s)
});
// Mark all places as "maybe init" if they are mutably borrowed. See #90752.
@ -282,12 +282,12 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
&& let LookupResult::Exact(mpi) = self.move_data().rev_lookup.find(place.as_ref())
{
on_all_children_bits(self.move_data(), mpi, |child| {
trans.gen_(child);
state.gen_(child);
})
}
}
fn apply_terminator_effect<'mir>(
fn apply_primary_terminator_effect<'mir>(
&mut self,
state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>,
@ -309,7 +309,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
fn apply_call_return_effect(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
_block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
@ -320,7 +320,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
self.move_data(),
self.move_data().rev_lookup.find(place.as_ref()),
|mpi| {
trans.gen_(mpi);
state.gen_(mpi);
},
);
});
@ -345,7 +345,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
};
let mut discriminants = enum_def.discriminants(self.tcx);
edge_effects.apply(|trans, edge| {
edge_effects.apply(|state, edge| {
let Some(value) = edge.value else {
return;
};
@ -363,25 +363,27 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
self.move_data(),
enum_place,
variant,
|mpi| trans.kill(mpi),
|mpi| state.kill(mpi),
);
});
}
}
/// There can be many more `MovePathIndex` than there are locals in a MIR body.
/// We use a mixed bitset to avoid paying too high a memory footprint.
pub type MaybeUninitializedPlacesDomain = MixedBitSet<MovePathIndex>;
impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
/// There can be many more `MovePathIndex` than there are locals in a MIR body.
/// We use a mixed bitset to avoid paying too high a memory footprint.
type Domain = MixedBitSet<MovePathIndex>;
type Domain = MaybeUninitializedPlacesDomain;
const NAME: &'static str = "maybe_uninit";
fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
// bottom = initialized (start_block_effect counters this at outset)
// bottom = initialized (`initialize_start_block` overwrites this on first entry)
MixedBitSet::new_empty(self.move_data().move_paths.len())
}
// sets on_entry bits for Arg places
// sets state bits for Arg places
fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
// set all bits to 1 (uninit) before gathering counter-evidence
state.insert_all();
@ -392,28 +394,28 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
});
}
fn apply_statement_effect(
fn apply_primary_statement_effect(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
_statement: &mir::Statement<'tcx>,
location: Location,
) {
drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
Self::update_bits(trans, path, s)
Self::update_bits(state, path, s)
});
// Unlike in `MaybeInitializedPlaces` above, we don't need to change the state when a
// mutable borrow occurs. Places cannot become uninitialized through a mutable reference.
}
fn apply_terminator_effect<'mir>(
fn apply_primary_terminator_effect<'mir>(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>,
location: Location,
) -> TerminatorEdges<'mir, 'tcx> {
drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| {
Self::update_bits(trans, path, s)
Self::update_bits(state, path, s)
});
if self.skip_unreachable_unwind.contains(location.block) {
let mir::TerminatorKind::Drop { target, unwind, .. } = terminator.kind else { bug!() };
@ -426,7 +428,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
fn apply_call_return_effect(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
_block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
@ -437,7 +439,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
self.move_data(),
self.move_data().rev_lookup.find(place.as_ref()),
|mpi| {
trans.kill(mpi);
state.kill(mpi);
},
);
});
@ -466,7 +468,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
};
let mut discriminants = enum_def.discriminants(self.tcx);
edge_effects.apply(|trans, edge| {
edge_effects.apply(|state, edge| {
let Some(value) = edge.value else {
return;
};
@ -484,16 +486,18 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
self.move_data(),
enum_place,
variant,
|mpi| trans.gen_(mpi),
|mpi| state.gen_(mpi),
);
});
}
}
/// There can be many more `InitIndex` than there are locals in a MIR body.
/// We use a mixed bitset to avoid paying too high a memory footprint.
pub type EverInitializedPlacesDomain = MixedBitSet<InitIndex>;
impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
/// There can be many more `InitIndex` than there are locals in a MIR body.
/// We use a mixed bitset to avoid paying too high a memory footprint.
type Domain = MixedBitSet<InitIndex>;
type Domain = EverInitializedPlacesDomain;
const NAME: &'static str = "ever_init";
@ -508,10 +512,10 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
}
}
#[instrument(skip(self, trans), level = "debug")]
fn apply_statement_effect(
#[instrument(skip(self, state), level = "debug")]
fn apply_primary_statement_effect(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
stmt: &mir::Statement<'tcx>,
location: Location,
) {
@ -521,7 +525,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
let rev_lookup = &move_data.rev_lookup;
debug!("initializes move_indexes {:?}", init_loc_map[location]);
trans.gen_all(init_loc_map[location].iter().copied());
state.gen_all(init_loc_map[location].iter().copied());
if let mir::StatementKind::StorageDead(local) = stmt.kind {
// End inits for StorageDead, so that an immutable variable can
@ -531,15 +535,15 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
"clears the ever initialized status of {:?}",
init_path_map[move_path_index]
);
trans.kill_all(init_path_map[move_path_index].iter().copied());
state.kill_all(init_path_map[move_path_index].iter().copied());
}
}
}
#[instrument(skip(self, trans, terminator), level = "debug")]
fn apply_terminator_effect<'mir>(
#[instrument(skip(self, state, terminator), level = "debug")]
fn apply_primary_terminator_effect<'mir>(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>,
location: Location,
) -> TerminatorEdges<'mir, 'tcx> {
@ -548,7 +552,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
let init_loc_map = &move_data.init_loc_map;
debug!(?term);
debug!("initializes move_indexes {:?}", init_loc_map[location]);
trans.gen_all(
state.gen_all(
init_loc_map[location]
.iter()
.filter(|init_index| {
@ -561,7 +565,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
fn apply_call_return_effect(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
block: mir::BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {
@ -570,7 +574,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
let call_loc = self.body.terminator_loc(block);
for init_index in &init_loc_map[call_loc] {
trans.gen_(*init_index);
state.gen_(*init_index);
}
}
}

View file

@ -40,33 +40,33 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
// No variables are live until we observe a use
}
fn apply_statement_effect(
fn apply_primary_statement_effect(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
statement: &mir::Statement<'tcx>,
location: Location,
) {
TransferFunction(trans).visit_statement(statement, location);
TransferFunction(state).visit_statement(statement, location);
}
fn apply_terminator_effect<'mir>(
fn apply_primary_terminator_effect<'mir>(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>,
location: Location,
) -> TerminatorEdges<'mir, 'tcx> {
TransferFunction(trans).visit_terminator(terminator, location);
TransferFunction(state).visit_terminator(terminator, location);
terminator.edges()
}
fn apply_call_return_effect(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
_block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
if let CallReturnPlaces::Yield(resume_place) = return_places {
YieldResumeEffect(trans).visit_place(
YieldResumeEffect(state).visit_place(
&resume_place,
PlaceContext::MutatingUse(MutatingUseContext::Yield),
Location::START,
@ -74,7 +74,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
} else {
return_places.for_each(|place| {
if let Some(local) = place.as_local() {
trans.kill(local);
state.kill(local);
}
});
}
@ -137,10 +137,10 @@ enum DefUse {
}
impl DefUse {
fn apply(trans: &mut BitSet<Local>, place: Place<'_>, context: PlaceContext) {
fn apply(state: &mut BitSet<Local>, place: Place<'_>, context: PlaceContext) {
match DefUse::for_place(place, context) {
Some(DefUse::Def) => trans.kill(place.local),
Some(DefUse::Use) => trans.gen_(place.local),
Some(DefUse::Def) => state.kill(place.local),
Some(DefUse::Use) => state.gen_(place.local),
None => {}
}
}
@ -232,9 +232,9 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
// No variables are live until we observe a use
}
fn apply_statement_effect(
fn apply_primary_statement_effect(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
statement: &mir::Statement<'tcx>,
location: Location,
) {
@ -258,34 +258,34 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
};
if let Some(destination) = destination {
if !destination.is_indirect()
&& !trans.contains(destination.local)
&& !state.contains(destination.local)
&& !self.always_live.contains(destination.local)
{
// This store is dead
return;
}
}
TransferFunction(trans).visit_statement(statement, location);
TransferFunction(state).visit_statement(statement, location);
}
fn apply_terminator_effect<'mir>(
fn apply_primary_terminator_effect<'mir>(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
terminator: &'mir mir::Terminator<'tcx>,
location: Location,
) -> TerminatorEdges<'mir, 'tcx> {
TransferFunction(trans).visit_terminator(terminator, location);
TransferFunction(state).visit_terminator(terminator, location);
terminator.edges()
}
fn apply_call_return_effect(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
_block: mir::BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
if let CallReturnPlaces::Yield(resume_place) = return_places {
YieldResumeEffect(trans).visit_place(
YieldResumeEffect(state).visit_place(
&resume_place,
PlaceContext::MutatingUse(MutatingUseContext::Yield),
Location::START,
@ -293,7 +293,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
} else {
return_places.for_each(|place| {
if let Some(local) = place.as_local() {
trans.remove(local);
state.remove(local);
}
});
}

View file

@ -5,7 +5,8 @@ mod storage_liveness;
pub use self::borrowed_locals::{MaybeBorrowedLocals, borrowed_locals};
pub use self::initialized::{
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
EverInitializedPlaces, EverInitializedPlacesDomain, MaybeInitializedPlaces,
MaybeUninitializedPlaces, MaybeUninitializedPlacesDomain,
};
pub use self::liveness::{
MaybeLiveLocals, MaybeTransitiveLiveLocals, TransferFunction as LivenessTransferFunction,

View file

@ -44,23 +44,23 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageLive<'a> {
BitSet::new_empty(body.local_decls.len())
}
fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) {
on_entry.union(&*self.always_live_locals);
fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
state.union(&*self.always_live_locals);
for arg in body.args_iter() {
on_entry.insert(arg);
state.insert(arg);
}
}
fn apply_statement_effect(
fn apply_primary_statement_effect(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
stmt: &Statement<'tcx>,
_: Location,
) {
match stmt.kind {
StatementKind::StorageLive(l) => trans.gen_(l),
StatementKind::StorageDead(l) => trans.kill(l),
StatementKind::StorageLive(l) => state.gen_(l),
StatementKind::StorageDead(l) => state.kill(l),
_ => (),
}
}
@ -86,25 +86,25 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageDead<'a> {
BitSet::new_empty(body.local_decls.len())
}
fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) {
fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
assert_eq!(body.local_decls.len(), self.always_live_locals.domain_size());
// Do not iterate on return place and args, as they are trivially always live.
for local in body.vars_and_temps_iter() {
if !self.always_live_locals.contains(local) {
on_entry.insert(local);
state.insert(local);
}
}
}
fn apply_statement_effect(
fn apply_primary_statement_effect(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
stmt: &Statement<'tcx>,
_: Location,
) {
match stmt.kind {
StatementKind::StorageLive(l) => trans.kill(l),
StatementKind::StorageDead(l) => trans.gen_(l),
StatementKind::StorageLive(l) => state.kill(l),
StatementKind::StorageDead(l) => state.gen_(l),
_ => (),
}
}
@ -134,31 +134,31 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
BitSet::new_empty(body.local_decls.len())
}
fn initialize_start_block(&self, body: &Body<'tcx>, on_entry: &mut Self::Domain) {
fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
// The resume argument is live on function entry (we don't care about
// the `self` argument)
for arg in body.args_iter().skip(1) {
on_entry.insert(arg);
state.insert(arg);
}
}
fn apply_before_statement_effect(
fn apply_early_statement_effect(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
stmt: &Statement<'tcx>,
loc: Location,
) {
// If a place is borrowed in a statement, it needs storage for that statement.
MaybeBorrowedLocals::transfer_function(trans).visit_statement(stmt, loc);
MaybeBorrowedLocals::transfer_function(state).visit_statement(stmt, loc);
match &stmt.kind {
StatementKind::StorageDead(l) => trans.kill(*l),
StatementKind::StorageDead(l) => state.kill(*l),
// If a place is assigned to in a statement, it needs storage for that statement.
StatementKind::Assign(box (place, _))
| StatementKind::SetDiscriminant { box place, .. }
| StatementKind::Deinit(box place) => {
trans.gen_(place.local);
state.gen_(place.local);
}
// Nothing to do for these. Match exhaustively so this fails to compile when new
@ -176,29 +176,29 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
}
}
fn apply_statement_effect(
fn apply_primary_statement_effect(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
_: &Statement<'tcx>,
loc: Location,
) {
// If we move from a place then it only stops needing storage *after*
// that statement.
self.check_for_move(trans, loc);
self.check_for_move(state, loc);
}
fn apply_before_terminator_effect(
fn apply_early_terminator_effect(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
terminator: &Terminator<'tcx>,
loc: Location,
) {
// If a place is borrowed in a terminator, it needs storage for that terminator.
MaybeBorrowedLocals::transfer_function(trans).visit_terminator(terminator, loc);
MaybeBorrowedLocals::transfer_function(state).visit_terminator(terminator, loc);
match &terminator.kind {
TerminatorKind::Call { destination, .. } => {
trans.gen_(destination.local);
state.gen_(destination.local);
}
// Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for
@ -213,7 +213,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
InlineAsmOperand::Out { place, .. }
| InlineAsmOperand::InOut { out_place: place, .. } => {
if let Some(place) = place {
trans.gen_(place.local);
state.gen_(place.local);
}
}
InlineAsmOperand::In { .. }
@ -242,9 +242,9 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
}
}
fn apply_terminator_effect<'t>(
fn apply_primary_terminator_effect<'t>(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
terminator: &'t Terminator<'tcx>,
loc: Location,
) -> TerminatorEdges<'t, 'tcx> {
@ -254,12 +254,12 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
// Since `propagate_call_unwind` doesn't exist, we have to kill the
// destination here, and then gen it again in `call_return_effect`.
TerminatorKind::Call { destination, .. } => {
trans.kill(destination.local);
state.kill(destination.local);
}
// The same applies to InlineAsm outputs.
TerminatorKind::InlineAsm { ref operands, .. } => {
CallReturnPlaces::InlineAsm(operands).for_each(|place| trans.kill(place.local));
CallReturnPlaces::InlineAsm(operands).for_each(|place| state.kill(place.local));
}
// Nothing to do for these. Match exhaustively so this fails to compile when new
@ -279,32 +279,32 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
| TerminatorKind::Unreachable => {}
}
self.check_for_move(trans, loc);
self.check_for_move(state, loc);
terminator.edges()
}
fn apply_call_return_effect(
&mut self,
trans: &mut Self::Domain,
state: &mut Self::Domain,
_block: BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
) {
return_places.for_each(|place| trans.gen_(place.local));
return_places.for_each(|place| state.gen_(place.local));
}
}
impl<'tcx> MaybeRequiresStorage<'_, 'tcx> {
/// Kill locals that are fully moved and have not been borrowed.
fn check_for_move(&mut self, trans: &mut <Self as Analysis<'tcx>>::Domain, loc: Location) {
fn check_for_move(&mut self, state: &mut <Self as Analysis<'tcx>>::Domain, loc: Location) {
let body = self.borrowed_locals.body();
let mut visitor = MoveVisitor { trans, borrowed_locals: &mut self.borrowed_locals };
let mut visitor = MoveVisitor { state, borrowed_locals: &mut self.borrowed_locals };
visitor.visit_location(body, loc);
}
}
struct MoveVisitor<'a, 'mir, 'tcx> {
borrowed_locals: &'a mut BorrowedLocalsResults<'mir, 'tcx>,
trans: &'a mut BitSet<Local>,
state: &'a mut BitSet<Local>,
}
impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx> {
@ -312,7 +312,7 @@ impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx> {
if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
self.borrowed_locals.seek_before_primary_effect(loc);
if !self.borrowed_locals.get().contains(local) {
self.trans.kill(local);
self.state.kill(local);
}
}
}

View file

@ -18,7 +18,7 @@ pub use self::drop_flag_effects::{
move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
};
pub use self::framework::{
Analysis, Backward, Direction, EntrySets, Forward, GenKill, JoinSemiLattice, MaybeReachable,
Analysis, Backward, Direction, EntryStates, Forward, GenKill, JoinSemiLattice, MaybeReachable,
Results, ResultsCursor, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
visit_results,
};

View file

@ -125,7 +125,7 @@ where
A: Analysis<'tcx, Domain = BitSet<N>>,
N: Idx,
{
fn visit_statement_after_primary_effect(
fn visit_after_primary_statement_effect(
&mut self,
_results: &mut Results<'tcx, A>,
state: &A::Domain,
@ -139,7 +139,7 @@ where
});
}
fn visit_terminator_after_primary_effect(
fn visit_after_primary_terminator_effect(
&mut self,
_results: &mut Results<'tcx, A>,
state: &A::Domain,

View file

@ -1,6 +1,5 @@
use rustc_ast::MetaItem;
use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::{self, Body, Local, Location};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span;
@ -254,7 +253,7 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals {
&self,
tcx: TyCtxt<'tcx>,
place: mir::Place<'tcx>,
state: &BitSet<Local>,
state: &Self::Domain,
call: PeekCall,
) {
info!(?place, "peek_at");

View file

@ -67,7 +67,7 @@ impl<V: Clone> Clone for StateData<V> {
}
}
impl<V: JoinSemiLattice + Clone + HasBottom> JoinSemiLattice for StateData<V> {
impl<V: JoinSemiLattice + Clone> JoinSemiLattice for StateData<V> {
fn join(&mut self, other: &Self) -> bool {
let mut changed = false;
#[allow(rustc::potential_query_instability)]
@ -342,7 +342,7 @@ impl<V: Clone + HasBottom> State<V> {
}
}
impl<V: JoinSemiLattice + Clone + HasBottom> JoinSemiLattice for State<V> {
impl<V: JoinSemiLattice + Clone> JoinSemiLattice for State<V> {
fn join(&mut self, other: &Self) -> bool {
match (&mut *self, other) {
(_, State::Unreachable) => false,