|
| 1 | +use std::fmt; |
| 2 | + |
1 | 3 | use rustc_data_structures::fx::FxIndexMap;
|
2 | 4 | use rustc_data_structures::graph;
|
3 | 5 | use rustc_index::bit_set::BitSet;
|
4 |
| -use rustc_middle::mir::{self, BasicBlock, Body, Location, Place, TerminatorEdges}; |
| 6 | +use rustc_middle::mir::{ |
| 7 | + self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges, |
| 8 | +}; |
5 | 9 | use rustc_middle::ty::{RegionVid, TyCtxt};
|
6 | 10 | use rustc_mir_dataflow::fmt::DebugWithContext;
|
7 | 11 | use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
|
8 |
| -use rustc_mir_dataflow::{Analysis, Forward, GenKill, Results, ResultsVisitable}; |
| 12 | +use rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice, SwitchIntEdgeEffects}; |
9 | 13 | use tracing::debug;
|
10 | 14 |
|
11 | 15 | use crate::{BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict};
|
12 | 16 |
|
13 |
| -/// The results of the dataflow analyses used by the borrow checker. |
14 |
| -pub(crate) struct BorrowckResults<'a, 'tcx> { |
15 |
| - pub(crate) borrows: Results<'tcx, Borrows<'a, 'tcx>>, |
16 |
| - pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'a, 'tcx>>, |
17 |
| - pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'a, 'tcx>>, |
18 |
| -} |
19 |
| - |
20 |
| -/// The transient state of the dataflow analyses used by the borrow checker. |
21 |
| -#[derive(Debug)] |
22 |
| -pub(crate) struct BorrowckDomain<'a, 'tcx> { |
23 |
| - pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain, |
24 |
| - pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain, |
25 |
| - pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain, |
| 17 | +// This analysis is different to most others. Its results aren't computed with |
| 18 | +// `iterate_to_fixpoint`, but are instead composed from the results of three sub-analyses that are |
| 19 | +// computed individually with `iterate_to_fixpoint`. |
| 20 | +pub(crate) struct Borrowck<'a, 'tcx> { |
| 21 | + pub(crate) borrows: Borrows<'a, 'tcx>, |
| 22 | + pub(crate) uninits: MaybeUninitializedPlaces<'a, 'tcx>, |
| 23 | + pub(crate) ever_inits: EverInitializedPlaces<'a, 'tcx>, |
26 | 24 | }
|
27 | 25 |
|
28 |
| -impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> { |
29 |
| - type Direction = Forward; |
| 26 | +impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { |
30 | 27 | type Domain = BorrowckDomain<'a, 'tcx>;
|
31 | 28 |
|
| 29 | + const NAME: &'static str = "borrowck"; |
| 30 | + |
32 | 31 | fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
|
33 | 32 | BorrowckDomain {
|
34 |
| - borrows: self.borrows.analysis.bottom_value(body), |
35 |
| - uninits: self.uninits.analysis.bottom_value(body), |
36 |
| - ever_inits: self.ever_inits.analysis.bottom_value(body), |
| 33 | + borrows: self.borrows.bottom_value(body), |
| 34 | + uninits: self.uninits.bottom_value(body), |
| 35 | + ever_inits: self.ever_inits.bottom_value(body), |
37 | 36 | }
|
38 | 37 | }
|
39 | 38 |
|
40 |
| - fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) { |
41 |
| - state.borrows.clone_from(self.borrows.entry_set_for_block(block)); |
42 |
| - state.uninits.clone_from(self.uninits.entry_set_for_block(block)); |
43 |
| - state.ever_inits.clone_from(self.ever_inits.entry_set_for_block(block)); |
| 39 | + fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _state: &mut Self::Domain) { |
| 40 | + // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use. |
| 41 | + unreachable!(); |
44 | 42 | }
|
45 | 43 |
|
46 |
| - fn reconstruct_before_statement_effect( |
| 44 | + fn apply_before_statement_effect( |
47 | 45 | &mut self,
|
48 | 46 | state: &mut Self::Domain,
|
49 | 47 | stmt: &mir::Statement<'tcx>,
|
50 | 48 | loc: Location,
|
51 | 49 | ) {
|
52 |
| - self.borrows.analysis.apply_before_statement_effect(&mut state.borrows, stmt, loc); |
53 |
| - self.uninits.analysis.apply_before_statement_effect(&mut state.uninits, stmt, loc); |
54 |
| - self.ever_inits.analysis.apply_before_statement_effect(&mut state.ever_inits, stmt, loc); |
| 50 | + self.borrows.apply_before_statement_effect(&mut state.borrows, stmt, loc); |
| 51 | + self.uninits.apply_before_statement_effect(&mut state.uninits, stmt, loc); |
| 52 | + self.ever_inits.apply_before_statement_effect(&mut state.ever_inits, stmt, loc); |
55 | 53 | }
|
56 | 54 |
|
57 |
| - fn reconstruct_statement_effect( |
| 55 | + fn apply_statement_effect( |
58 | 56 | &mut self,
|
59 | 57 | state: &mut Self::Domain,
|
60 | 58 | stmt: &mir::Statement<'tcx>,
|
61 | 59 | loc: Location,
|
62 | 60 | ) {
|
63 |
| - self.borrows.analysis.apply_statement_effect(&mut state.borrows, stmt, loc); |
64 |
| - self.uninits.analysis.apply_statement_effect(&mut state.uninits, stmt, loc); |
65 |
| - self.ever_inits.analysis.apply_statement_effect(&mut state.ever_inits, stmt, loc); |
| 61 | + self.borrows.apply_statement_effect(&mut state.borrows, stmt, loc); |
| 62 | + self.uninits.apply_statement_effect(&mut state.uninits, stmt, loc); |
| 63 | + self.ever_inits.apply_statement_effect(&mut state.ever_inits, stmt, loc); |
66 | 64 | }
|
67 | 65 |
|
68 |
| - fn reconstruct_before_terminator_effect( |
| 66 | + fn apply_before_terminator_effect( |
69 | 67 | &mut self,
|
70 | 68 | state: &mut Self::Domain,
|
71 | 69 | term: &mir::Terminator<'tcx>,
|
72 | 70 | loc: Location,
|
73 | 71 | ) {
|
74 |
| - self.borrows.analysis.apply_before_terminator_effect(&mut state.borrows, term, loc); |
75 |
| - self.uninits.analysis.apply_before_terminator_effect(&mut state.uninits, term, loc); |
76 |
| - self.ever_inits.analysis.apply_before_terminator_effect(&mut state.ever_inits, term, loc); |
| 72 | + self.borrows.apply_before_terminator_effect(&mut state.borrows, term, loc); |
| 73 | + self.uninits.apply_before_terminator_effect(&mut state.uninits, term, loc); |
| 74 | + self.ever_inits.apply_before_terminator_effect(&mut state.ever_inits, term, loc); |
77 | 75 | }
|
78 | 76 |
|
79 |
| - fn reconstruct_terminator_effect( |
| 77 | + fn apply_terminator_effect<'mir>( |
80 | 78 | &mut self,
|
81 | 79 | state: &mut Self::Domain,
|
82 |
| - term: &mir::Terminator<'tcx>, |
| 80 | + term: &'mir mir::Terminator<'tcx>, |
83 | 81 | loc: Location,
|
| 82 | + ) -> TerminatorEdges<'mir, 'tcx> { |
| 83 | + self.borrows.apply_terminator_effect(&mut state.borrows, term, loc); |
| 84 | + self.uninits.apply_terminator_effect(&mut state.uninits, term, loc); |
| 85 | + self.ever_inits.apply_terminator_effect(&mut state.ever_inits, term, loc); |
| 86 | + |
| 87 | + // This return value doesn't matter. It's only used by `iterate_to_fixpoint`, which this |
| 88 | + // analysis doesn't use. |
| 89 | + TerminatorEdges::None |
| 90 | + } |
| 91 | + |
| 92 | + fn apply_call_return_effect( |
| 93 | + &mut self, |
| 94 | + _state: &mut Self::Domain, |
| 95 | + _block: BasicBlock, |
| 96 | + _return_places: CallReturnPlaces<'_, 'tcx>, |
| 97 | + ) { |
| 98 | + // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use. |
| 99 | + unreachable!(); |
| 100 | + } |
| 101 | + |
| 102 | + fn apply_switch_int_edge_effects( |
| 103 | + &mut self, |
| 104 | + _block: BasicBlock, |
| 105 | + _discr: &mir::Operand<'tcx>, |
| 106 | + _apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>, |
84 | 107 | ) {
|
85 |
| - self.borrows.analysis.apply_terminator_effect(&mut state.borrows, term, loc); |
86 |
| - self.uninits.analysis.apply_terminator_effect(&mut state.uninits, term, loc); |
87 |
| - self.ever_inits.analysis.apply_terminator_effect(&mut state.ever_inits, term, loc); |
| 108 | + // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use. |
| 109 | + unreachable!(); |
88 | 110 | }
|
89 | 111 | }
|
90 | 112 |
|
| 113 | +impl JoinSemiLattice for BorrowckDomain<'_, '_> { |
| 114 | + fn join(&mut self, _other: &Self) -> bool { |
| 115 | + // This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use. |
| 116 | + unreachable!(); |
| 117 | + } |
| 118 | +} |
| 119 | + |
| 120 | +impl<'tcx, C> DebugWithContext<C> for BorrowckDomain<'_, 'tcx> |
| 121 | +where |
| 122 | + C: rustc_mir_dataflow::move_paths::HasMoveData<'tcx>, |
| 123 | +{ |
| 124 | + fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 125 | + f.write_str("borrows: ")?; |
| 126 | + self.borrows.fmt_with(ctxt, f)?; |
| 127 | + f.write_str(" uninits: ")?; |
| 128 | + self.uninits.fmt_with(ctxt, f)?; |
| 129 | + f.write_str(" ever_inits: ")?; |
| 130 | + self.ever_inits.fmt_with(ctxt, f)?; |
| 131 | + Ok(()) |
| 132 | + } |
| 133 | + |
| 134 | + fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 135 | + if self == old { |
| 136 | + return Ok(()); |
| 137 | + } |
| 138 | + |
| 139 | + if self.borrows != old.borrows { |
| 140 | + f.write_str("borrows: ")?; |
| 141 | + self.borrows.fmt_diff_with(&old.borrows, ctxt, f)?; |
| 142 | + f.write_str("\n")?; |
| 143 | + } |
| 144 | + |
| 145 | + if self.uninits != old.uninits { |
| 146 | + f.write_str("uninits: ")?; |
| 147 | + self.uninits.fmt_diff_with(&old.uninits, ctxt, f)?; |
| 148 | + f.write_str("\n")?; |
| 149 | + } |
| 150 | + |
| 151 | + if self.ever_inits != old.ever_inits { |
| 152 | + f.write_str("ever_inits: ")?; |
| 153 | + self.ever_inits.fmt_diff_with(&old.ever_inits, ctxt, f)?; |
| 154 | + f.write_str("\n")?; |
| 155 | + } |
| 156 | + |
| 157 | + Ok(()) |
| 158 | + } |
| 159 | +} |
| 160 | + |
| 161 | +/// The transient state of the dataflow analyses used by the borrow checker. |
| 162 | +#[derive(Clone, Debug, PartialEq, Eq)] |
| 163 | +pub(crate) struct BorrowckDomain<'a, 'tcx> { |
| 164 | + pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain, |
| 165 | + pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain, |
| 166 | + pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain, |
| 167 | +} |
| 168 | + |
91 | 169 | rustc_index::newtype_index! {
|
92 | 170 | #[orderable]
|
93 | 171 | #[debug_format = "bw{}"]
|
|
0 commit comments