rustc_mir_dataflow

Trait Analysis

source
pub trait Analysis<'tcx> {
    type Domain: Clone + JoinSemiLattice;
    type Direction: Direction = Forward;

    const NAME: &'static str;

    // Required methods
    fn bottom_value(&self, body: &Body<'tcx>) -> Self::Domain;
    fn initialize_start_block(
        &self,
        body: &Body<'tcx>,
        state: &mut Self::Domain,
    );
    fn apply_statement_effect(
        &mut self,
        state: &mut Self::Domain,
        statement: &Statement<'tcx>,
        location: Location,
    );

    // Provided methods
    fn apply_before_statement_effect(
        &mut self,
        _state: &mut Self::Domain,
        _statement: &Statement<'tcx>,
        _location: Location,
    ) { ... }
    fn apply_terminator_effect<'mir>(
        &mut self,
        _state: &mut Self::Domain,
        terminator: &'mir Terminator<'tcx>,
        _location: Location,
    ) -> TerminatorEdges<'mir, 'tcx> { ... }
    fn apply_before_terminator_effect(
        &mut self,
        _state: &mut Self::Domain,
        _terminator: &Terminator<'tcx>,
        _location: Location,
    ) { ... }
    fn apply_call_return_effect(
        &mut self,
        _state: &mut Self::Domain,
        _block: BasicBlock,
        _return_places: CallReturnPlaces<'_, 'tcx>,
    ) { ... }
    fn apply_switch_int_edge_effects(
        &mut self,
        _block: BasicBlock,
        _discr: &Operand<'tcx>,
        _apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
    ) { ... }
    fn into_engine<'mir>(
        self,
        tcx: TyCtxt<'tcx>,
        body: &'mir Body<'tcx>,
    ) -> Engine<'mir, 'tcx, Self>
       where Self: Sized { ... }
}
Expand description

A dataflow problem with an arbitrarily complex transfer function.

This trait specifies the lattice on which this analysis operates (the domain), its initial value at the entry point of each basic block, and various operations.

§Convergence

When implementing this trait it’s possible to choose a transfer function such that the analysis does not reach fixpoint. To guarantee convergence, your transfer functions must maintain the following invariant:

If the dataflow state before some point in the program changes to be greater than the prior state before that point, the dataflow state after that point must also change to be greater than the prior state after that point.

This invariant guarantees that the dataflow state at a given point in the program increases monotonically until fixpoint is reached. Note that this monotonicity requirement only applies to the same point in the program at different points in time. The dataflow state at a given point in the program may or may not be greater than the state at any preceding point.

Required Associated Constants§

source

const NAME: &'static str

A descriptive name for this analysis. Used only for debugging.

This name should be brief and contain no spaces, periods or other characters that are not suitable as part of a filename.

Required Associated Types§

source

type Domain: Clone + JoinSemiLattice

The type that holds the dataflow state at any given point in the program.

Provided Associated Types§

source

type Direction: Direction = Forward

The direction of this analysis. Either Forward or Backward.

Required Methods§

source

fn bottom_value(&self, body: &Body<'tcx>) -> Self::Domain

Returns the initial value of the dataflow state upon entry to each basic block.

source

fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain)

Mutates the initial value of the dataflow state upon entry to the START_BLOCK.

For backward analyses, initial state (besides the bottom value) is not yet supported. Trying to mutate the initial state will result in a panic.

source

fn apply_statement_effect( &mut self, state: &mut Self::Domain, statement: &Statement<'tcx>, location: Location, )

Updates the current dataflow state with the effect of evaluating a statement.

Provided Methods§

source

fn apply_before_statement_effect( &mut self, _state: &mut Self::Domain, _statement: &Statement<'tcx>, _location: Location, )

Updates the current dataflow state with an effect 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_statement_effect.

source

fn apply_terminator_effect<'mir>( &mut self, _state: &mut Self::Domain, terminator: &'mir Terminator<'tcx>, _location: Location, ) -> TerminatorEdges<'mir, 'tcx>

Updates the current dataflow state with the effect of evaluating a terminator.

The effect of a successful return from a Call terminator should not be accounted for 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.

source

fn apply_before_terminator_effect( &mut self, _state: &mut Self::Domain, _terminator: &Terminator<'tcx>, _location: Location, )

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.

source

fn apply_call_return_effect( &mut self, _state: &mut Self::Domain, _block: BasicBlock, _return_places: CallReturnPlaces<'_, 'tcx>, )

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.

source

fn apply_switch_int_edge_effects( &mut self, _block: BasicBlock, _discr: &Operand<'tcx>, _apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>, )

Updates the current dataflow state with the effect of taking a particular branch in a SwitchInt terminator.

Unlike the other edge-specific effects, which are allowed to mutate Self::Domain directly, overriders of this method must pass a callback to SwitchIntEdgeEffects::apply. The callback will be run once for each outgoing edge and will have access to the dataflow state that will be propagated along that edge.

This interface is somewhat more complex than the other visitor-like “effect” methods. However, it is both more ergonomic—callers don’t need to recompute or cache information about a given SwitchInt terminator for each one of its edges—and more efficient—the engine doesn’t need to clone the exit state for a block unless SwitchIntEdgeEffects::apply is actually called.

source

fn into_engine<'mir>( self, tcx: TyCtxt<'tcx>, body: &'mir Body<'tcx>, ) -> Engine<'mir, 'tcx, Self>
where Self: Sized,

Creates an Engine to find the fixpoint for this dataflow problem.

You shouldn’t need to override this. Its purpose is to enable method chaining like so:

let results = MyAnalysis::new(tcx, body)
    .into_engine(tcx, body, def_id)
    .iterate_to_fixpoint()
    .into_results_cursor(body);

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§

source§

impl<'a, 'tcx> Analysis<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx>

source§

const NAME: &'static str = "definite_init"

source§

type Domain = Dual<BitSet<MovePathIndex>>

source§

impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a>

source§

const NAME: &'static str = "transitive liveness"

source§

type Domain = BitSet<Local>

source§

type Direction = Backward

source§

impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageDead<'a>

source§

const NAME: &'static str = "maybe_storage_dead"

source§

type Domain = BitSet<Local>

source§

impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageLive<'a>

source§

const NAME: &'static str = "maybe_storage_live"

source§

type Domain = BitSet<Local>

source§

impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals

source§

const NAME: &'static str = "maybe_borrowed_locals"

source§

type Domain = BitSet<Local>

source§

impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx>

source§

const NAME: &'static str = "ever_init"

source§

type Domain = ChunkedBitSet<InitIndex>

source§

impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx>

source§

impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx>

source§

const NAME: &'static str = "maybe_uninit"

source§

type Domain = ChunkedBitSet<MovePathIndex>

source§

impl<'tcx> Analysis<'tcx> for MaybeLiveLocals

source§

const NAME: &'static str = "liveness"

source§

type Domain = BitSet<Local>

source§

type Direction = Backward

source§

impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx>

source§

const NAME: &'static str = "requires_storage"

source§

type Domain = BitSet<Local>

source§

impl<'tcx, T: ValueAnalysis<'tcx>> Analysis<'tcx> for ValueAnalysisWrapper<T>

source§

const NAME: &'static str = T::NAME

source§

type Domain = State<<T as ValueAnalysis<'tcx>>::Value>