Rollup merge of #132134 - nnethercote:rm-ResultsVisitable, r=cjgillot

Remove `ResultsVisitable`

`ResultsVisitable` has annoyed me for a while. This PR removes it. Details in the individual commits.

r? `@cjgillot.`
This commit is contained in:
Matthias Krüger 2024-11-16 21:05:44 +01:00 committed by GitHub
commit 5c81dbf4fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 291 additions and 304 deletions

View File

@ -1,93 +1,171 @@
use std::fmt;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::graph;
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::{self, BasicBlock, Body, Location, Place, TerminatorEdges};
use rustc_middle::mir::{
self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
};
use rustc_middle::ty::{RegionVid, TyCtxt};
use rustc_mir_dataflow::fmt::DebugWithContext;
use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
use rustc_mir_dataflow::{Analysis, Forward, GenKill, Results, ResultsVisitable};
use rustc_mir_dataflow::{Analysis, GenKill, JoinSemiLattice, SwitchIntEdgeEffects};
use tracing::debug;
use crate::{BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict};
/// The results of the dataflow analyses used by the borrow checker.
pub(crate) struct BorrowckResults<'a, 'tcx> {
pub(crate) borrows: Results<'tcx, Borrows<'a, 'tcx>>,
pub(crate) uninits: Results<'tcx, MaybeUninitializedPlaces<'a, 'tcx>>,
pub(crate) ever_inits: Results<'tcx, EverInitializedPlaces<'a, 'tcx>>,
// This analysis is different to most others. Its results aren't computed with
// `iterate_to_fixpoint`, but are instead composed from the results of three sub-analyses that are
// computed individually with `iterate_to_fixpoint`.
pub(crate) struct Borrowck<'a, 'tcx> {
pub(crate) borrows: Borrows<'a, 'tcx>,
pub(crate) uninits: MaybeUninitializedPlaces<'a, 'tcx>,
pub(crate) ever_inits: EverInitializedPlaces<'a, 'tcx>,
}
impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> {
type Domain = BorrowckDomain<'a, 'tcx>;
const NAME: &'static str = "borrowck";
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
BorrowckDomain {
borrows: self.borrows.bottom_value(body),
uninits: self.uninits.bottom_value(body),
ever_inits: self.ever_inits.bottom_value(body),
}
}
fn initialize_start_block(&self, _body: &mir::Body<'tcx>, _state: &mut Self::Domain) {
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
unreachable!();
}
fn apply_before_statement_effect(
&mut self,
state: &mut Self::Domain,
stmt: &mir::Statement<'tcx>,
loc: Location,
) {
self.borrows.apply_before_statement_effect(&mut state.borrows, stmt, loc);
self.uninits.apply_before_statement_effect(&mut state.uninits, stmt, loc);
self.ever_inits.apply_before_statement_effect(&mut state.ever_inits, stmt, loc);
}
fn apply_statement_effect(
&mut self,
state: &mut Self::Domain,
stmt: &mir::Statement<'tcx>,
loc: Location,
) {
self.borrows.apply_statement_effect(&mut state.borrows, stmt, loc);
self.uninits.apply_statement_effect(&mut state.uninits, stmt, loc);
self.ever_inits.apply_statement_effect(&mut state.ever_inits, stmt, loc);
}
fn apply_before_terminator_effect(
&mut self,
state: &mut Self::Domain,
term: &mir::Terminator<'tcx>,
loc: Location,
) {
self.borrows.apply_before_terminator_effect(&mut state.borrows, term, loc);
self.uninits.apply_before_terminator_effect(&mut state.uninits, term, loc);
self.ever_inits.apply_before_terminator_effect(&mut state.ever_inits, term, loc);
}
fn apply_terminator_effect<'mir>(
&mut self,
state: &mut Self::Domain,
term: &'mir mir::Terminator<'tcx>,
loc: Location,
) -> TerminatorEdges<'mir, 'tcx> {
self.borrows.apply_terminator_effect(&mut state.borrows, term, loc);
self.uninits.apply_terminator_effect(&mut state.uninits, term, loc);
self.ever_inits.apply_terminator_effect(&mut state.ever_inits, term, loc);
// This return value doesn't matter. It's only used by `iterate_to_fixpoint`, which this
// analysis doesn't use.
TerminatorEdges::None
}
fn apply_call_return_effect(
&mut self,
_state: &mut Self::Domain,
_block: BasicBlock,
_return_places: CallReturnPlaces<'_, 'tcx>,
) {
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
unreachable!();
}
fn apply_switch_int_edge_effects(
&mut self,
_block: BasicBlock,
_discr: &mir::Operand<'tcx>,
_apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
) {
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
unreachable!();
}
}
impl JoinSemiLattice for BorrowckDomain<'_, '_> {
fn join(&mut self, _other: &Self) -> bool {
// This is only reachable from `iterate_to_fixpoint`, which this analysis doesn't use.
unreachable!();
}
}
impl<'tcx, C> DebugWithContext<C> for BorrowckDomain<'_, 'tcx>
where
C: rustc_mir_dataflow::move_paths::HasMoveData<'tcx>,
{
fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("borrows: ")?;
self.borrows.fmt_with(ctxt, f)?;
f.write_str(" uninits: ")?;
self.uninits.fmt_with(ctxt, f)?;
f.write_str(" ever_inits: ")?;
self.ever_inits.fmt_with(ctxt, f)?;
Ok(())
}
fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self == old {
return Ok(());
}
if self.borrows != old.borrows {
f.write_str("borrows: ")?;
self.borrows.fmt_diff_with(&old.borrows, ctxt, f)?;
f.write_str("\n")?;
}
if self.uninits != old.uninits {
f.write_str("uninits: ")?;
self.uninits.fmt_diff_with(&old.uninits, ctxt, f)?;
f.write_str("\n")?;
}
if self.ever_inits != old.ever_inits {
f.write_str("ever_inits: ")?;
self.ever_inits.fmt_diff_with(&old.ever_inits, ctxt, f)?;
f.write_str("\n")?;
}
Ok(())
}
}
/// The transient state of the dataflow analyses used by the borrow checker.
#[derive(Debug)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct BorrowckDomain<'a, 'tcx> {
pub(crate) borrows: <Borrows<'a, 'tcx> as Analysis<'tcx>>::Domain,
pub(crate) uninits: <MaybeUninitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
pub(crate) ever_inits: <EverInitializedPlaces<'a, 'tcx> as Analysis<'tcx>>::Domain,
}
impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> {
type Direction = Forward;
type Domain = BorrowckDomain<'a, 'tcx>;
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
BorrowckDomain {
borrows: self.borrows.analysis.bottom_value(body),
uninits: self.uninits.analysis.bottom_value(body),
ever_inits: self.ever_inits.analysis.bottom_value(body),
}
}
fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) {
state.borrows.clone_from(self.borrows.entry_set_for_block(block));
state.uninits.clone_from(self.uninits.entry_set_for_block(block));
state.ever_inits.clone_from(self.ever_inits.entry_set_for_block(block));
}
fn reconstruct_before_statement_effect(
&mut self,
state: &mut Self::Domain,
stmt: &mir::Statement<'tcx>,
loc: Location,
) {
self.borrows.analysis.apply_before_statement_effect(&mut state.borrows, stmt, loc);
self.uninits.analysis.apply_before_statement_effect(&mut state.uninits, stmt, loc);
self.ever_inits.analysis.apply_before_statement_effect(&mut state.ever_inits, stmt, loc);
}
fn reconstruct_statement_effect(
&mut self,
state: &mut Self::Domain,
stmt: &mir::Statement<'tcx>,
loc: Location,
) {
self.borrows.analysis.apply_statement_effect(&mut state.borrows, stmt, loc);
self.uninits.analysis.apply_statement_effect(&mut state.uninits, stmt, loc);
self.ever_inits.analysis.apply_statement_effect(&mut state.ever_inits, stmt, loc);
}
fn reconstruct_before_terminator_effect(
&mut self,
state: &mut Self::Domain,
term: &mir::Terminator<'tcx>,
loc: Location,
) {
self.borrows.analysis.apply_before_terminator_effect(&mut state.borrows, term, loc);
self.uninits.analysis.apply_before_terminator_effect(&mut state.uninits, term, loc);
self.ever_inits.analysis.apply_before_terminator_effect(&mut state.ever_inits, term, loc);
}
fn reconstruct_terminator_effect(
&mut self,
state: &mut Self::Domain,
term: &mir::Terminator<'tcx>,
loc: Location,
) {
self.borrows.analysis.apply_terminator_effect(&mut state.borrows, term, loc);
self.uninits.analysis.apply_terminator_effect(&mut state.uninits, term, loc);
self.ever_inits.analysis.apply_terminator_effect(&mut state.ever_inits, term, loc);
}
}
rustc_index::newtype_index! {
#[orderable]
#[debug_format = "bw{}"]

View File

@ -36,13 +36,13 @@ use rustc_middle::mir::*;
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
use rustc_middle::{bug, span_bug};
use rustc_mir_dataflow::Analysis;
use rustc_mir_dataflow::impls::{
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
};
use rustc_mir_dataflow::move_paths::{
InitIndex, InitLocation, LookupResult, MoveData, MoveOutIndex, MovePathIndex,
};
use rustc_mir_dataflow::{Analysis, EntrySets, Results, ResultsVisitor, visit_results};
use rustc_session::lint::builtin::UNUSED_MUT;
use rustc_span::{Span, Symbol};
use smallvec::SmallVec;
@ -50,7 +50,7 @@ use tracing::{debug, instrument};
use crate::borrow_set::{BorrowData, BorrowSet};
use crate::consumers::{BodyWithBorrowckFacts, ConsumerOptions};
use crate::dataflow::{BorrowIndex, BorrowckDomain, BorrowckResults, Borrows};
use crate::dataflow::{BorrowIndex, Borrowck, BorrowckDomain, Borrows};
use crate::diagnostics::{AccessKind, IllegalMoveOriginKind, MoveError, RegionName};
use crate::location::LocationTable;
use crate::nll::PoloniusOutput;
@ -221,6 +221,10 @@ fn do_mir_borrowck<'tcx>(
consumer_options,
);
// `flow_inits` is large, so we drop it as soon as possible. This reduces
// peak memory usage significantly on some benchmarks.
drop(flow_inits);
// Dump MIR results into a file, if that is enabled. This let us
// write unit-tests, as well as helping with debugging.
nll::dump_nll_mir(&infcx, body, &regioncx, &opt_closure_req, &borrow_set);
@ -229,27 +233,6 @@ fn do_mir_borrowck<'tcx>(
// information.
nll::dump_annotation(&infcx, body, &regioncx, &opt_closure_req, &opaque_type_values, diags);
// The various `flow_*` structures can be large. We drop `flow_inits` here
// so it doesn't overlap with the others below. This reduces peak memory
// usage significantly on some benchmarks.
drop(flow_inits);
let flow_borrows = Borrows::new(tcx, body, &regioncx, &borrow_set).iterate_to_fixpoint(
tcx,
body,
Some("borrowck"),
);
let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(
tcx,
body,
Some("borrowck"),
);
let flow_ever_inits = EverInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(
tcx,
body,
Some("borrowck"),
);
let movable_coroutine =
// The first argument is the coroutine type passed by value
if let Some(local) = body.local_decls.raw.get(1)
@ -334,16 +317,11 @@ fn do_mir_borrowck<'tcx>(
// Compute and report region errors, if any.
mbcx.report_region_errors(nll_errors);
let mut results = BorrowckResults {
ever_inits: flow_ever_inits,
uninits: flow_uninits,
borrows: flow_borrows,
};
rustc_mir_dataflow::visit_results(
let mut flow_results = get_flow_results(tcx, body, &move_data, &borrow_set, &regioncx);
visit_results(
body,
traversal::reverse_postorder(body).map(|(bb, _)| bb),
&mut results,
&mut flow_results,
&mut mbcx,
);
@ -426,6 +404,47 @@ fn do_mir_borrowck<'tcx>(
(result, body_with_facts)
}
fn get_flow_results<'a, 'tcx>(
tcx: TyCtxt<'tcx>,
body: &'a Body<'tcx>,
move_data: &'a MoveData<'tcx>,
borrow_set: &'a BorrowSet<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
) -> Results<'tcx, Borrowck<'a, 'tcx>> {
// We compute these three analyses individually, but them combine them into
// a single results so that `mbcx` can visit them all together.
let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
tcx,
body,
Some("borrowck"),
);
let uninits = MaybeUninitializedPlaces::new(tcx, body, move_data).iterate_to_fixpoint(
tcx,
body,
Some("borrowck"),
);
let ever_inits = EverInitializedPlaces::new(body, move_data).iterate_to_fixpoint(
tcx,
body,
Some("borrowck"),
);
let analysis = Borrowck {
borrows: borrows.analysis,
uninits: uninits.analysis,
ever_inits: ever_inits.analysis,
};
assert_eq!(borrows.entry_sets.len(), uninits.entry_sets.len());
assert_eq!(borrows.entry_sets.len(), ever_inits.entry_sets.len());
let entry_sets: EntrySets<'_, Borrowck<'_, '_>> =
itertools::izip!(borrows.entry_sets, uninits.entry_sets, ever_inits.entry_sets)
.map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
.collect();
Results { analysis, entry_sets }
}
pub(crate) struct BorrowckInferCtxt<'tcx> {
pub(crate) infcx: InferCtxt<'tcx>,
pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
@ -588,14 +607,10 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
// 2. loans made in overlapping scopes do not conflict
// 3. assignments do not affect things loaned out as immutable
// 4. moves do not affect things loaned out in any way
impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
for MirBorrowckCtxt<'a, '_, 'tcx>
{
type Domain = BorrowckDomain<'a, 'tcx>;
impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
fn visit_statement_before_primary_effect(
&mut self,
_results: &mut R,
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
state: &BorrowckDomain<'a, 'tcx>,
stmt: &'a Statement<'tcx>,
location: Location,
@ -667,7 +682,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
fn visit_terminator_before_primary_effect(
&mut self,
_results: &mut R,
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
state: &BorrowckDomain<'a, 'tcx>,
term: &'a Terminator<'tcx>,
loc: Location,
@ -780,7 +795,7 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
fn visit_terminator_after_primary_effect(
&mut self,
_results: &mut R,
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
state: &BorrowckDomain<'a, 'tcx>,
term: &'a Terminator<'tcx>,
loc: Location,

View File

@ -4,8 +4,8 @@ use rustc_middle::mir::{
self, BasicBlock, CallReturnPlaces, Location, SwitchTargets, TerminatorEdges,
};
use super::visitor::{ResultsVisitable, ResultsVisitor};
use super::{Analysis, Effect, EffectIndex, SwitchIntTarget};
use super::visitor::ResultsVisitor;
use super::{Analysis, Effect, EffectIndex, Results, SwitchIntTarget};
pub trait Direction {
const IS_FORWARD: bool;
@ -33,14 +33,14 @@ pub trait Direction {
where
A: Analysis<'tcx>;
fn visit_results_in_block<'mir, 'tcx, D, R>(
state: &mut D,
fn visit_results_in_block<'mir, 'tcx, A>(
state: &mut A::Domain,
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
results: &mut R,
vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
results: &mut Results<'tcx, A>,
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
) where
R: ResultsVisitable<'tcx, Domain = D>;
A: Analysis<'tcx>;
fn join_state_into_successors_of<'tcx, A>(
analysis: &mut A,
@ -53,7 +53,7 @@ pub trait Direction {
A: Analysis<'tcx>;
}
/// Dataflow that runs from the exit of a block (the terminator), to its entry (the first statement).
/// Dataflow that runs from the exit of a block (terminator), to its entry (the first statement).
pub struct Backward;
impl Direction for Backward {
@ -157,32 +157,32 @@ impl Direction for Backward {
analysis.apply_statement_effect(state, statement, location);
}
fn visit_results_in_block<'mir, 'tcx, D, R>(
state: &mut D,
fn visit_results_in_block<'mir, 'tcx, A>(
state: &mut A::Domain,
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
results: &mut R,
vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
results: &mut Results<'tcx, A>,
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
) where
R: ResultsVisitable<'tcx, Domain = D>,
A: Analysis<'tcx>,
{
results.reset_to_block_entry(state, block);
state.clone_from(results.entry_set_for_block(block));
vis.visit_block_end(state);
// Terminator
let loc = Location { block, statement_index: block_data.statements.len() };
let term = block_data.terminator();
results.reconstruct_before_terminator_effect(state, term, loc);
results.analysis.apply_before_terminator_effect(state, term, loc);
vis.visit_terminator_before_primary_effect(results, state, term, loc);
results.reconstruct_terminator_effect(state, term, loc);
results.analysis.apply_terminator_effect(state, term, loc);
vis.visit_terminator_after_primary_effect(results, state, term, loc);
for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
let loc = Location { block, statement_index };
results.reconstruct_before_statement_effect(state, stmt, loc);
results.analysis.apply_before_statement_effect(state, stmt, loc);
vis.visit_statement_before_primary_effect(results, state, stmt, loc);
results.reconstruct_statement_effect(state, stmt, loc);
results.analysis.apply_statement_effect(state, stmt, loc);
vis.visit_statement_after_primary_effect(results, state, stmt, loc);
}
@ -389,32 +389,32 @@ impl Direction for Forward {
}
}
fn visit_results_in_block<'mir, 'tcx, F, R>(
state: &mut F,
fn visit_results_in_block<'mir, 'tcx, A>(
state: &mut A::Domain,
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
results: &mut R,
vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = F>,
results: &mut Results<'tcx, A>,
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
) where
R: ResultsVisitable<'tcx, Domain = F>,
A: Analysis<'tcx>,
{
results.reset_to_block_entry(state, block);
state.clone_from(results.entry_set_for_block(block));
vis.visit_block_start(state);
for (statement_index, stmt) in block_data.statements.iter().enumerate() {
let loc = Location { block, statement_index };
results.reconstruct_before_statement_effect(state, stmt, loc);
results.analysis.apply_before_statement_effect(state, stmt, loc);
vis.visit_statement_before_primary_effect(results, state, stmt, loc);
results.reconstruct_statement_effect(state, stmt, loc);
results.analysis.apply_statement_effect(state, stmt, loc);
vis.visit_statement_after_primary_effect(results, state, stmt, loc);
}
let loc = Location { block, statement_index: block_data.statements.len() };
let term = block_data.terminator();
results.reconstruct_before_terminator_effect(state, term, loc);
results.analysis.apply_before_terminator_effect(state, term, loc);
vis.visit_terminator_before_primary_effect(results, state, term, loc);
results.reconstruct_terminator_effect(state, term, loc);
results.analysis.apply_terminator_effect(state, term, loc);
vis.visit_terminator_after_primary_effect(results, state, term, loc);
vis.visit_block_end(state);

View File

@ -544,20 +544,18 @@ impl<D> StateDiffCollector<D> {
}
}
impl<'tcx, A> ResultsVisitor<'_, 'tcx, Results<'tcx, A>> for StateDiffCollector<A::Domain>
impl<'tcx, A> ResultsVisitor<'_, 'tcx, A> for StateDiffCollector<A::Domain>
where
A: Analysis<'tcx>,
A::Domain: DebugWithContext<A>,
{
type Domain = A::Domain;
fn visit_block_start(&mut self, state: &Self::Domain) {
fn visit_block_start(&mut self, state: &A::Domain) {
if A::Direction::IS_FORWARD {
self.prev_state.clone_from(state);
}
}
fn visit_block_end(&mut self, state: &Self::Domain) {
fn visit_block_end(&mut self, state: &A::Domain) {
if A::Direction::IS_BACKWARD {
self.prev_state.clone_from(state);
}
@ -566,7 +564,7 @@ where
fn visit_statement_before_primary_effect(
&mut self,
results: &mut Results<'tcx, A>,
state: &Self::Domain,
state: &A::Domain,
_statement: &mir::Statement<'tcx>,
_location: Location,
) {
@ -579,7 +577,7 @@ where
fn visit_statement_after_primary_effect(
&mut self,
results: &mut Results<'tcx, A>,
state: &Self::Domain,
state: &A::Domain,
_statement: &mir::Statement<'tcx>,
_location: Location,
) {
@ -590,7 +588,7 @@ where
fn visit_terminator_before_primary_effect(
&mut self,
results: &mut Results<'tcx, A>,
state: &Self::Domain,
state: &A::Domain,
_terminator: &mir::Terminator<'tcx>,
_location: Location,
) {
@ -603,7 +601,7 @@ where
fn visit_terminator_after_primary_effect(
&mut self,
results: &mut Results<'tcx, A>,
state: &Self::Domain,
state: &A::Domain,
_terminator: &mir::Terminator<'tcx>,
_location: Location,
) {

View File

@ -55,8 +55,8 @@ mod visitor;
pub use self::cursor::ResultsCursor;
pub use self::direction::{Backward, Direction, Forward};
pub use self::lattice::{JoinSemiLattice, MaybeReachable};
pub use self::results::Results;
pub use self::visitor::{ResultsVisitable, ResultsVisitor, visit_results};
pub use self::results::{EntrySets, Results};
pub use self::visitor::{ResultsVisitor, visit_results};
/// Analysis domains are all bitsets of various kinds. This trait holds
/// operations needed by all of them.

View File

@ -18,7 +18,7 @@ use crate::errors::{
DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
};
type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as Analysis<'tcx>>::Domain>;
/// A dataflow analysis that has converged to fixpoint.
#[derive(Clone)]
@ -27,7 +27,7 @@ where
A: Analysis<'tcx>,
{
pub analysis: A,
pub(super) entry_sets: EntrySets<'tcx, A>,
pub entry_sets: EntrySets<'tcx, A>,
}
impl<'tcx, A> Results<'tcx, A>
@ -51,7 +51,7 @@ where
&mut self,
body: &'mir mir::Body<'tcx>,
blocks: impl IntoIterator<Item = BasicBlock>,
vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>,
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
) {
visit_results(body, blocks, self, vis)
}
@ -59,7 +59,7 @@ where
pub fn visit_reachable_with<'mir>(
&mut self,
body: &'mir mir::Body<'tcx>,
vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>,
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
) {
let blocks = traversal::reachable(body);
visit_results(body, blocks.map(|(bb, _)| bb), self, vis)

View File

@ -4,15 +4,15 @@ 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, D, R>(
pub fn visit_results<'mir, 'tcx, A>(
body: &'mir mir::Body<'tcx>,
blocks: impl IntoIterator<Item = BasicBlock>,
results: &mut R,
vis: &mut impl ResultsVisitor<'mir, 'tcx, R, Domain = D>,
results: &mut Results<'tcx, A>,
vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
) where
R: ResultsVisitable<'tcx, Domain = D>,
A: Analysis<'tcx>,
{
let mut state = results.bottom_value(body);
let mut state = results.analysis.bottom_value(body);
#[cfg(debug_assertions)]
let reachable_blocks = mir::traversal::reachable_as_bitset(body);
@ -22,23 +22,23 @@ pub fn visit_results<'mir, 'tcx, D, R>(
assert!(reachable_blocks.contains(block));
let block_data = &body[block];
R::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
A::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
}
}
/// A visitor over the results of an `Analysis`. The type parameter `R` is the results type being
/// visited.
pub trait ResultsVisitor<'mir, 'tcx, R> {
type Domain;
fn visit_block_start(&mut self, _state: &Self::Domain) {}
/// A visitor over the results of an `Analysis`.
pub trait ResultsVisitor<'mir, 'tcx, A>
where
A: Analysis<'tcx>,
{
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(
&mut self,
_results: &mut R,
_state: &Self::Domain,
_results: &mut Results<'tcx, A>,
_state: &A::Domain,
_statement: &'mir mir::Statement<'tcx>,
_location: Location,
) {
@ -48,19 +48,19 @@ pub trait ResultsVisitor<'mir, 'tcx, R> {
/// statement applied to `state`.
fn visit_statement_after_primary_effect(
&mut self,
_results: &mut R,
_state: &Self::Domain,
_results: &mut Results<'tcx, A>,
_state: &A::Domain,
_statement: &'mir mir::Statement<'tcx>,
_location: Location,
) {
}
/// Called with the `before_terminator_effect` of the given terminator applied to `state` but not
/// its `terminator_effect`.
/// Called with the `before_terminator_effect` of the given terminator applied to `state` but
/// not its `terminator_effect`.
fn visit_terminator_before_primary_effect(
&mut self,
_results: &mut R,
_state: &Self::Domain,
_results: &mut Results<'tcx, A>,
_state: &A::Domain,
_terminator: &'mir mir::Terminator<'tcx>,
_location: Location,
) {
@ -72,109 +72,12 @@ pub trait ResultsVisitor<'mir, 'tcx, R> {
/// The `call_return_effect` (if one exists) will *not* be applied to `state`.
fn visit_terminator_after_primary_effect(
&mut self,
_results: &mut R,
_state: &Self::Domain,
_results: &mut Results<'tcx, A>,
_state: &A::Domain,
_terminator: &'mir mir::Terminator<'tcx>,
_location: Location,
) {
}
fn visit_block_end(&mut self, _state: &Self::Domain) {}
}
/// Things that can be visited by a `ResultsVisitor`.
///
/// This trait exists so that we can visit the results of one or more dataflow analyses
/// simultaneously.
pub trait ResultsVisitable<'tcx> {
type Direction: Direction;
type Domain;
/// Creates an empty `Domain` to hold the transient state for these dataflow results.
///
/// The value of the newly created `Domain` will be overwritten by `reset_to_block_entry`
/// before it can be observed by a `ResultsVisitor`.
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain;
fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock);
fn reconstruct_before_statement_effect(
&mut self,
state: &mut Self::Domain,
statement: &mir::Statement<'tcx>,
location: Location,
);
fn reconstruct_statement_effect(
&mut self,
state: &mut Self::Domain,
statement: &mir::Statement<'tcx>,
location: Location,
);
fn reconstruct_before_terminator_effect(
&mut self,
state: &mut Self::Domain,
terminator: &mir::Terminator<'tcx>,
location: Location,
);
fn reconstruct_terminator_effect(
&mut self,
state: &mut Self::Domain,
terminator: &mir::Terminator<'tcx>,
location: Location,
);
}
impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A>
where
A: Analysis<'tcx>,
{
type Domain = A::Domain;
type Direction = A::Direction;
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
self.analysis.bottom_value(body)
}
fn reset_to_block_entry(&self, state: &mut Self::Domain, block: BasicBlock) {
state.clone_from(self.entry_set_for_block(block));
}
fn reconstruct_before_statement_effect(
&mut self,
state: &mut Self::Domain,
stmt: &mir::Statement<'tcx>,
loc: Location,
) {
self.analysis.apply_before_statement_effect(state, stmt, loc);
}
fn reconstruct_statement_effect(
&mut self,
state: &mut Self::Domain,
stmt: &mir::Statement<'tcx>,
loc: Location,
) {
self.analysis.apply_statement_effect(state, stmt, loc);
}
fn reconstruct_before_terminator_effect(
&mut self,
state: &mut Self::Domain,
term: &mir::Terminator<'tcx>,
loc: Location,
) {
self.analysis.apply_before_terminator_effect(state, term, loc);
}
fn reconstruct_terminator_effect(
&mut self,
state: &mut Self::Domain,
term: &mir::Terminator<'tcx>,
loc: Location,
) {
self.analysis.apply_terminator_effect(state, term, loc);
}
fn visit_block_end(&mut self, _state: &A::Domain) {}
}

View File

@ -18,8 +18,8 @@ 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, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results,
ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
Analysis, Backward, Direction, EntrySets, Forward, GenKill, JoinSemiLattice, MaybeReachable,
Results, ResultsCursor, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
visit_results,
};
use self::move_paths::MoveData;

View File

@ -3,7 +3,7 @@ use rustc_index::interval::SparseIntervalMatrix;
use rustc_index::{Idx, IndexVec};
use rustc_middle::mir::{self, BasicBlock, Body, Location};
use crate::framework::{ResultsVisitable, ResultsVisitor, visit_results};
use crate::framework::{Analysis, Results, ResultsVisitor, visit_results};
/// Maps between a `Location` and a `PointIndex` (and vice versa).
pub struct DenseLocationMap {
@ -95,14 +95,14 @@ rustc_index::newtype_index! {
}
/// Add points depending on the result of the given dataflow analysis.
pub fn save_as_intervals<'tcx, N, R>(
pub fn save_as_intervals<'tcx, N, A>(
elements: &DenseLocationMap,
body: &mir::Body<'tcx>,
mut results: R,
mut results: Results<'tcx, A>,
) -> SparseIntervalMatrix<N, PointIndex>
where
N: Idx,
R: ResultsVisitable<'tcx, Domain = BitSet<N>>,
A: Analysis<'tcx, Domain = BitSet<N>>,
{
let values = SparseIntervalMatrix::new(elements.num_points());
let mut visitor = Visitor { elements, values };
@ -120,16 +120,15 @@ struct Visitor<'a, N: Idx> {
values: SparseIntervalMatrix<N, PointIndex>,
}
impl<'mir, 'tcx, R, N> ResultsVisitor<'mir, 'tcx, R> for Visitor<'_, N>
impl<'mir, 'tcx, A, N> ResultsVisitor<'mir, 'tcx, A> for Visitor<'_, N>
where
A: Analysis<'tcx, Domain = BitSet<N>>,
N: Idx,
{
type Domain = BitSet<N>;
fn visit_statement_after_primary_effect(
&mut self,
_results: &mut R,
state: &Self::Domain,
_results: &mut Results<'tcx, A>,
state: &A::Domain,
_statement: &'mir mir::Statement<'tcx>,
location: Location,
) {
@ -142,8 +141,8 @@ where
fn visit_terminator_after_primary_effect(
&mut self,
_results: &mut R,
state: &Self::Domain,
_results: &mut Results<'tcx, A>,
state: &A::Domain,
_terminator: &'mir mir::Terminator<'tcx>,
location: Location,
) {

View File

@ -68,11 +68,11 @@ use rustc_middle::ty::{
self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, TypingMode,
};
use rustc_middle::{bug, span_bug};
use rustc_mir_dataflow::Analysis;
use rustc_mir_dataflow::impls::{
MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
};
use rustc_mir_dataflow::storage::always_storage_live_locals;
use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor};
use rustc_span::Span;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::symbol::sym;
@ -817,9 +817,9 @@ impl ops::Deref for CoroutineSavedLocals {
/// computation; see `CoroutineLayout` for more.
fn compute_storage_conflicts<'mir, 'tcx>(
body: &'mir Body<'tcx>,
saved_locals: &CoroutineSavedLocals,
saved_locals: &'mir CoroutineSavedLocals,
always_live_locals: BitSet<Local>,
mut requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
mut requires_storage: Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
) -> BitMatrix<CoroutineSavedLocal, CoroutineSavedLocal> {
assert_eq!(body.local_decls.len(), saved_locals.domain_size());
@ -877,15 +877,13 @@ struct StorageConflictVisitor<'a, 'tcx> {
eligible_storage_live: BitSet<Local>,
}
impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>>
for StorageConflictVisitor<'a, 'tcx>
{
type Domain = BitSet<Local>;
fn visit_statement_before_primary_effect(
&mut self,
_results: &mut R,
state: &Self::Domain,
_results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
state: &BitSet<Local>,
_statement: &'a Statement<'tcx>,
loc: Location,
) {
@ -894,8 +892,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
fn visit_terminator_before_primary_effect(
&mut self,
_results: &mut R,
state: &Self::Domain,
_results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
state: &BitSet<Local>,
_terminator: &'a Terminator<'tcx>,
loc: Location,
) {

View File

@ -941,16 +941,12 @@ fn try_write_constant<'tcx>(
interp_ok(())
}
impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx>>>
for Collector<'_, 'tcx>
{
type Domain = State<FlatSet<Scalar>>;
impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> {
#[instrument(level = "trace", skip(self, results, statement))]
fn visit_statement_before_primary_effect(
&mut self,
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
state: &Self::Domain,
state: &State<FlatSet<Scalar>>,
statement: &'mir Statement<'tcx>,
location: Location,
) {
@ -972,7 +968,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx
fn visit_statement_after_primary_effect(
&mut self,
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
state: &Self::Domain,
state: &State<FlatSet<Scalar>>,
statement: &'mir Statement<'tcx>,
location: Location,
) {
@ -997,7 +993,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx
fn visit_terminator_before_primary_effect(
&mut self,
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
state: &Self::Domain,
state: &State<FlatSet<Scalar>>,
terminator: &'mir Terminator<'tcx>,
location: Location,
) {