about summary refs log tree commit diff
path: root/compiler/rustc_mir_dataflow/src/framework/visitor.rs
blob: fbb9e4108726d55d1d862910e65fec7b73833e3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use rustc_middle::mir::{self, BasicBlock, Location, traversal};

use super::{Analysis, Direction, Results};

/// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the
/// dataflow state at that location.
pub fn visit_results<'mir, 'tcx, A>(
    body: &'mir mir::Body<'tcx>,
    blocks: impl IntoIterator<Item = BasicBlock>,
    analysis: &mut A,
    results: &Results<A::Domain>,
    vis: &mut impl ResultsVisitor<'tcx, A>,
) where
    A: Analysis<'tcx>,
{
    let mut state = analysis.bottom_value(body);

    #[cfg(debug_assertions)]
    let reachable_blocks = mir::traversal::reachable_as_bitset(body);

    for block in blocks {
        #[cfg(debug_assertions)]
        assert!(reachable_blocks.contains(block));

        let block_data = &body[block];
        state.clone_from(&results[block]);
        A::Direction::visit_results_in_block(&mut state, block, block_data, analysis, vis);
    }
}

/// Like `visit_results`, but only for reachable blocks.
pub fn visit_reachable_results<'mir, 'tcx, A>(
    body: &'mir mir::Body<'tcx>,
    analysis: &mut A,
    results: &Results<A::Domain>,
    vis: &mut impl ResultsVisitor<'tcx, A>,
) where
    A: Analysis<'tcx>,
{
    let blocks = traversal::reachable(body).map(|(bb, _)| bb);
    visit_results(body, blocks, analysis, results, vis)
}

/// A visitor over the results of an `Analysis`. Use this when you want to inspect domain values in
/// many or all locations; use `ResultsCursor` if you want to inspect domain values only in certain
/// locations.
pub trait ResultsVisitor<'tcx, A>
where
    A: Analysis<'tcx>,
{
    fn visit_block_start(&mut self, _state: &A::Domain) {}

    /// Called after the "early" effect of the given statement is applied to `state`.
    fn visit_after_early_statement_effect(
        &mut self,
        _analysis: &mut A,
        _state: &A::Domain,
        _statement: &mir::Statement<'tcx>,
        _location: Location,
    ) {
    }

    /// Called after the "primary" effect of the given statement is applied to `state`.
    fn visit_after_primary_statement_effect(
        &mut self,
        _analysis: &mut A,
        _state: &A::Domain,
        _statement: &mir::Statement<'tcx>,
        _location: Location,
    ) {
    }

    /// Called after the "early" effect of the given terminator is applied to `state`.
    fn visit_after_early_terminator_effect(
        &mut self,
        _analysis: &mut A,
        _state: &A::Domain,
        _terminator: &mir::Terminator<'tcx>,
        _location: Location,
    ) {
    }

    /// 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_after_primary_terminator_effect(
        &mut self,
        _analysis: &mut A,
        _state: &A::Domain,
        _terminator: &mir::Terminator<'tcx>,
        _location: Location,
    ) {
    }

    fn visit_block_end(&mut self, _state: &A::Domain) {}
}