From 874b03ec28beba617951efef505fe3e320900454 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 10 Oct 2024 11:21:16 +1100 Subject: [PATCH 1/7] Remove `ResultsCursor::contains`. It's hardly worth it, and it needs to be removed so that `GenKillAnalysis` can be removed. --- compiler/rustc_mir_dataflow/src/framework/cursor.rs | 11 ----------- .../rustc_mir_dataflow/src/impls/storage_liveness.rs | 2 +- compiler/rustc_mir_transform/src/elaborate_drops.rs | 2 +- compiler/rustc_mir_transform/src/ref_prop.rs | 2 +- .../clippy/clippy_utils/src/mir/possible_borrower.rs | 4 ++-- 5 files changed, 5 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index 7cfaef22689fa..5ebb343f4e195 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -7,7 +7,6 @@ use rustc_index::bit_set::BitSet; use rustc_middle::mir::{self, BasicBlock, Location}; use super::{Analysis, Direction, Effect, EffectIndex, Results}; -use crate::framework::BitSetExt; /// Allows random access inspection of the results of a dataflow analysis. /// @@ -221,16 +220,6 @@ where } } -impl<'mir, 'tcx, A> ResultsCursor<'mir, 'tcx, A> -where - A: crate::GenKillAnalysis<'tcx>, - A::Domain: BitSetExt, -{ - pub fn contains(&self, elem: A::Idx) -> bool { - self.get().contains(elem) - } -} - #[derive(Clone, Copy, Debug)] struct CursorPosition { block: BasicBlock, diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 34ac5809a2e2b..fe223a3abd8a1 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -364,7 +364,7 @@ where fn visit_local(&mut self, local: Local, context: PlaceContext, loc: Location) { if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context { self.borrowed_locals.seek_before_primary_effect(loc); - if !self.borrowed_locals.contains(local) { + if !self.borrowed_locals.get().contains(local) { self.trans.kill(local); } } diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index c35aec42408ca..f4ac4d9fee6fb 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -133,7 +133,7 @@ impl InitializationData<'_, '_> { } fn maybe_live_dead(&self, path: MovePathIndex) -> (bool, bool) { - (self.inits.contains(path), self.uninits.contains(path)) + (self.inits.get().contains(path), self.uninits.get().contains(path)) } } diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index a62a892716fbf..53e53d9d5ba8b 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -179,7 +179,7 @@ fn compute_replacement<'tcx>( } else { // This is a proper dereference. We can only allow it if `target` is live. maybe_dead.seek_after_primary_effect(loc); - let maybe_dead = maybe_dead.contains(target.local); + let maybe_dead = maybe_dead.get().contains(target.local); !maybe_dead } }; diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs index 6bb434a466fdf..a00196c4b511d 100644 --- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs +++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs @@ -213,7 +213,7 @@ impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> { self.bitset.0.clear(); let maybe_live = &mut self.maybe_live; if let Some(bitset) = self.map.get(&borrowed) { - for b in bitset.iter().filter(move |b| maybe_live.contains(*b)) { + for b in bitset.iter().filter(move |b| maybe_live.get().contains(*b)) { self.bitset.0.insert(b); } } else { @@ -238,6 +238,6 @@ impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> { pub fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool { self.maybe_live.seek_after_primary_effect(at); - self.maybe_live.contains(local) + self.maybe_live.get().contains(local) } } From e0b83c34c3320de1f16c8f888d12f3b1aee18a26 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 10 Oct 2024 06:41:03 +1100 Subject: [PATCH 2/7] Remove `Engine::new_gen_kill`. This is an alternative to `Engine::new_generic` for gen/kill analyses. It's supposed to be an optimization, but it has negligible effect. The commit merges `Engine::new_generic` into `Engine::new`. This allows the removal of various other things: `GenKillSet`, `gen_kill_statement_effects_in_block`, `is_cfg_cyclic`. --- compiler/rustc_middle/src/mir/basic_blocks.rs | 7 -- .../src/framework/direction.rs | 66 ++------------ .../src/framework/engine.rs | 88 ++----------------- .../rustc_mir_dataflow/src/framework/mod.rs | 53 +---------- 4 files changed, 17 insertions(+), 197 deletions(-) diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 4602c918160b7..3eb563d7d6e57 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -26,7 +26,6 @@ type SwitchSources = FxHashMap<(BasicBlock, BasicBlock), SmallVec<[Option; struct Cache { predecessors: OnceLock, switch_sources: OnceLock, - is_cyclic: OnceLock, reverse_postorder: OnceLock>, dominators: OnceLock>, } @@ -37,12 +36,6 @@ impl<'tcx> BasicBlocks<'tcx> { BasicBlocks { basic_blocks, cache: Cache::default() } } - /// Returns true if control-flow graph contains a cycle reachable from the `START_BLOCK`. - #[inline] - pub fn is_cfg_cyclic(&self) -> bool { - *self.cache.is_cyclic.get_or_init(|| graph::is_cyclic(self)) - } - pub fn dominators(&self) -> &Dominators { self.cache.dominators.get_or_init(|| dominators(self)) } diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 88a9a78f8ad62..3e01f0512c46f 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -5,7 +5,7 @@ use rustc_middle::mir::{ }; use super::visitor::{ResultsVisitable, ResultsVisitor}; -use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget}; +use super::{Analysis, Effect, EffectIndex, SwitchIntTarget}; pub trait Direction { const IS_FORWARD: bool; @@ -29,19 +29,10 @@ pub trait Direction { state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - statement_effect: Option<&dyn Fn(BasicBlock, &mut A::Domain)>, ) -> TerminatorEdges<'mir, 'tcx> where A: Analysis<'tcx>; - fn gen_kill_statement_effects_in_block<'tcx, A>( - analysis: &mut A, - trans: &mut GenKillSet, - block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - ) where - A: GenKillAnalysis<'tcx>; - fn visit_results_in_block<'mir, 'tcx, D, R>( state: &mut D, block: BasicBlock, @@ -73,7 +64,6 @@ impl Direction for Backward { state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - statement_effect: Option<&dyn Fn(BasicBlock, &mut A::Domain)>, ) -> TerminatorEdges<'mir, 'tcx> where A: Analysis<'tcx>, @@ -82,31 +72,12 @@ impl Direction for Backward { 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); - if let Some(statement_effect) = statement_effect { - statement_effect(block, state) - } else { - 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); - } - } - edges - } - - fn gen_kill_statement_effects_in_block<'tcx, A>( - analysis: &mut A, - trans: &mut GenKillSet, - block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - ) where - A: GenKillAnalysis<'tcx>, - { for (statement_index, statement) in block_data.statements.iter().enumerate().rev() { let location = Location { block, statement_index }; - analysis.before_statement_effect(trans, statement, location); - analysis.statement_effect(trans, statement, location); + analysis.apply_before_statement_effect(state, statement, location); + analysis.apply_statement_effect(state, statement, location); } + edges } fn apply_effects_in_range<'tcx, A>( @@ -330,42 +301,21 @@ impl Direction for Forward { state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - statement_effect: Option<&dyn Fn(BasicBlock, &mut A::Domain)>, ) -> TerminatorEdges<'mir, 'tcx> where A: Analysis<'tcx>, { - if let Some(statement_effect) = statement_effect { - statement_effect(block, state) - } else { - 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); - } + 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); } - 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) } - fn gen_kill_statement_effects_in_block<'tcx, A>( - analysis: &mut A, - trans: &mut GenKillSet, - block: BasicBlock, - block_data: &mir::BasicBlockData<'tcx>, - ) where - A: GenKillAnalysis<'tcx>, - { - for (statement_index, statement) in block_data.statements.iter().enumerate() { - let location = Location { block, statement_index }; - analysis.before_statement_effect(trans, statement, location); - analysis.statement_effect(trans, statement, location); - } - } - fn apply_effects_in_range<'tcx, A>( analysis: &mut A, state: &mut A::Domain, diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 9d50e57d66868..d6853b6ef829f 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -5,7 +5,7 @@ use std::path::PathBuf; use rustc_data_structures::work_queue::WorkQueue; use rustc_hir::def_id::DefId; -use rustc_index::{Idx, IndexVec}; +use rustc_index::IndexVec; use rustc_middle::bug; use rustc_middle::mir::{self, BasicBlock, create_dump_file, dump_enabled, traversal}; use rustc_middle::ty::TyCtxt; @@ -16,13 +16,12 @@ use {rustc_ast as ast, rustc_graphviz as dot}; use super::fmt::DebugWithContext; use super::{ - Analysis, AnalysisDomain, Direction, GenKill, GenKillAnalysis, GenKillSet, JoinSemiLattice, - ResultsCursor, ResultsVisitor, graphviz, visit_results, + Analysis, AnalysisDomain, Direction, JoinSemiLattice, ResultsCursor, ResultsVisitor, graphviz, + visit_results, }; use crate::errors::{ DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter, }; -use crate::framework::BitSetExt; type EntrySets<'tcx, A> = IndexVec>::Domain>; @@ -82,53 +81,6 @@ where entry_sets: IndexVec, pass_name: Option<&'static str>, analysis: A, - - /// Cached, cumulative transfer functions for each block. - // - // FIXME(ecstaticmorse): This boxed `Fn` trait object is invoked inside a tight loop for - // gen/kill problems on cyclic CFGs. This is not ideal, but it doesn't seem to degrade - // performance in practice. I've tried a few ways to avoid this, but they have downsides. See - // the message for the commit that added this FIXME for more information. - apply_statement_trans_for_block: Option>, -} - -impl<'mir, 'tcx, A, D, T> Engine<'mir, 'tcx, A> -where - A: GenKillAnalysis<'tcx, Idx = T, Domain = D>, - D: Clone + JoinSemiLattice + GenKill + BitSetExt, - T: Idx, -{ - /// Creates a new `Engine` to solve a gen-kill dataflow problem. - pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, mut analysis: A) -> Self { - // If there are no back-edges in the control-flow graph, we only ever need to apply the - // transfer function for each block exactly once (assuming that we process blocks in RPO). - // - // In this case, there's no need to compute the block transfer functions ahead of time. - if !body.basic_blocks.is_cfg_cyclic() { - return Self::new(tcx, body, analysis, None); - } - - // Otherwise, compute and store the cumulative transfer function for each block. - - let identity = GenKillSet::identity(analysis.domain_size(body)); - let mut trans_for_block = IndexVec::from_elem(identity, &body.basic_blocks); - - for (block, block_data) in body.basic_blocks.iter_enumerated() { - let trans = &mut trans_for_block[block]; - A::Direction::gen_kill_statement_effects_in_block( - &mut analysis, - trans, - block, - block_data, - ); - } - - let apply_trans = Box::new(move |bb: BasicBlock, state: &mut A::Domain| { - trans_for_block[bb].apply(state); - }); - - Self::new(tcx, body, analysis, Some(apply_trans as Box<_>)) - } } impl<'mir, 'tcx, A, D> Engine<'mir, 'tcx, A> @@ -138,19 +90,7 @@ where { /// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer /// function. - /// - /// Gen-kill problems should use `new_gen_kill`, which will coalesce transfer functions for - /// better performance. - pub fn new_generic(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, analysis: A) -> Self { - Self::new(tcx, body, analysis, None) - } - - fn new( - tcx: TyCtxt<'tcx>, - body: &'mir mir::Body<'tcx>, - analysis: A, - apply_statement_trans_for_block: Option>, - ) -> Self { + pub(crate) fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, analysis: A) -> Self { let mut entry_sets = IndexVec::from_fn_n(|_| analysis.bottom_value(body), body.basic_blocks.len()); analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]); @@ -160,7 +100,7 @@ where bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); } - Engine { analysis, tcx, body, pass_name: None, entry_sets, apply_statement_trans_for_block } + Engine { analysis, tcx, body, pass_name: None, entry_sets } } /// Adds an identifier to the graphviz output for this particular run of a dataflow analysis. @@ -177,14 +117,7 @@ where where A::Domain: DebugWithContext, { - let Engine { - mut analysis, - body, - mut entry_sets, - tcx, - apply_statement_trans_for_block, - pass_name, - } = self; + let Engine { mut analysis, body, mut entry_sets, tcx, pass_name } = self; let mut dirty_queue: WorkQueue = WorkQueue::with_none(body.basic_blocks.len()); @@ -213,13 +146,8 @@ where state.clone_from(&entry_sets[bb]); // Apply the block transfer function, using the cached one if it exists. - let edges = A::Direction::apply_effects_in_block( - &mut analysis, - &mut state, - bb, - bb_data, - apply_statement_trans_for_block.as_deref(), - ); + let edges = + A::Direction::apply_effects_in_block(&mut analysis, &mut state, bb, bb_data); A::Direction::join_state_into_successors_of( &mut analysis, diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index d0472e35fe00a..459261a64ff4a 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -242,7 +242,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { where Self: Sized, { - Engine::new_generic(tcx, body, self) + Engine::new(tcx, body, self) } } @@ -376,19 +376,6 @@ where ) { self.switch_int_edge_effects(block, discr, edge_effects); } - - /* Extension methods */ - #[inline] - fn into_engine<'mir>( - self, - tcx: TyCtxt<'tcx>, - body: &'mir mir::Body<'tcx>, - ) -> Engine<'mir, 'tcx, Self> - where - Self: Sized, - { - Engine::new_gen_kill(tcx, body, self) - } } /// The legal operations for a transfer function in a gen/kill problem. @@ -422,44 +409,6 @@ pub trait GenKill { } } -/// Stores a transfer function for a gen/kill problem. -/// -/// Calling `gen_`/`kill` on a `GenKillSet` will "build up" a transfer function so that it can be -/// applied multiple times efficiently. When there are multiple calls to `gen_` and/or `kill` for -/// the same element, the most recent one takes precedence. -#[derive(Clone)] -pub struct GenKillSet { - gen_: HybridBitSet, - kill: HybridBitSet, -} - -impl GenKillSet { - /// Creates a new transfer function that will leave the dataflow state unchanged. - pub fn identity(universe: usize) -> Self { - GenKillSet { - gen_: HybridBitSet::new_empty(universe), - kill: HybridBitSet::new_empty(universe), - } - } - - pub fn apply(&self, state: &mut impl BitSetExt) { - state.union(&self.gen_); - state.subtract(&self.kill); - } -} - -impl GenKill for GenKillSet { - fn gen_(&mut self, elem: T) { - self.gen_.insert(elem); - self.kill.remove(elem); - } - - fn kill(&mut self, elem: T) { - self.kill.insert(elem); - self.gen_.remove(elem); - } -} - impl GenKill for BitSet { fn gen_(&mut self, elem: T) { self.insert(elem); From 13968b4a70ad6be54efa8d9d388963040d5b6473 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 10 Oct 2024 06:46:08 +1100 Subject: [PATCH 3/7] Tweak `GenKillAnalysis` method arguments. `GenKillAnalysis` has very similar methods to `Analysis`, but the first two have a notable difference: the second argument is `&mut impl GenKill` instead of `&mut Self::Domain`. But thanks to the previous commit, this difference is no longer necessary. --- compiler/rustc_borrowck/src/dataflow.rs | 4 ++-- .../rustc_mir_dataflow/src/framework/mod.rs | 9 ++++---- .../src/impls/borrowed_locals.rs | 2 +- .../src/impls/initialized.rs | 8 +++---- .../rustc_mir_dataflow/src/impls/liveness.rs | 2 +- .../src/impls/storage_liveness.rs | 23 ++++--------------- 6 files changed, 16 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 5ea48d3fc7e94..b0f5f638e6764 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -518,7 +518,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { fn before_statement_effect( &mut self, - trans: &mut impl GenKill, + trans: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, ) { @@ -527,7 +527,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { fn statement_effect( &mut self, - trans: &mut impl GenKill, + trans: &mut Self::Domain, stmt: &mir::Statement<'tcx>, location: Location, ) { diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 459261a64ff4a..9d79b6f44a684 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -260,19 +260,18 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { fn domain_size(&self, body: &mir::Body<'tcx>) -> usize; - /// See `Analysis::apply_statement_effect`. Note how the second arg differs. + /// See `Analysis::apply_statement_effect`. fn statement_effect( &mut self, - trans: &mut impl GenKill, + trans: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, ); - /// See `Analysis::apply_before_statement_effect`. Note how the second arg - /// differs. + /// See `Analysis::apply_before_statement_effect`. fn before_statement_effect( &mut self, - _trans: &mut impl GenKill, + _trans: &mut Self::Domain, _statement: &mir::Statement<'tcx>, _location: Location, ) { diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 8b082ef2667a3..dc9a1d5f3ad9a 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -43,7 +43,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals { fn statement_effect( &mut self, - trans: &mut impl GenKill, + trans: &mut Self::Domain, statement: &Statement<'tcx>, location: Location, ) { diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 25e8726cf6162..bb61e7e94320e 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -338,7 +338,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { fn statement_effect( &mut self, - trans: &mut impl GenKill, + trans: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, ) { @@ -475,7 +475,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { fn statement_effect( &mut self, - trans: &mut impl GenKill, + trans: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, ) { @@ -602,7 +602,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { fn statement_effect( &mut self, - trans: &mut impl GenKill, + trans: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, ) { @@ -672,7 +672,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { #[instrument(skip(self, trans), level = "debug")] fn statement_effect( &mut self, - trans: &mut impl GenKill, + trans: &mut Self::Domain, stmt: &mir::Statement<'tcx>, location: Location, ) { diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 1559c131a3783..af46d5543ba43 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -50,7 +50,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { fn statement_effect( &mut self, - trans: &mut impl GenKill, + trans: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, ) { diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index fe223a3abd8a1..833cb968e3600 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -46,12 +46,7 @@ impl<'a, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { body.local_decls.len() } - fn statement_effect( - &mut self, - trans: &mut impl GenKill, - stmt: &Statement<'tcx>, - _: Location, - ) { + fn statement_effect(&mut self, trans: &mut Self::Domain, stmt: &Statement<'tcx>, _: Location) { match stmt.kind { StatementKind::StorageLive(l) => trans.gen_(l), StatementKind::StorageDead(l) => trans.kill(l), @@ -117,12 +112,7 @@ impl<'a, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead<'a> { body.local_decls.len() } - fn statement_effect( - &mut self, - trans: &mut impl GenKill, - stmt: &Statement<'tcx>, - _: Location, - ) { + fn statement_effect(&mut self, trans: &mut Self::Domain, stmt: &Statement<'tcx>, _: Location) { match stmt.kind { StatementKind::StorageLive(l) => trans.kill(l), StatementKind::StorageDead(l) => trans.gen_(l), @@ -192,7 +182,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { fn before_statement_effect( &mut self, - trans: &mut impl GenKill, + trans: &mut Self::Domain, stmt: &Statement<'tcx>, loc: Location, ) { @@ -223,12 +213,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { } } - fn statement_effect( - &mut self, - trans: &mut impl GenKill, - _: &Statement<'tcx>, - loc: Location, - ) { + fn statement_effect(&mut self, trans: &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); From 525f655866fe933937bd67e54b7f51a44781c7bb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 10 Oct 2024 10:14:58 +1100 Subject: [PATCH 4/7] Minimize use of `GenKill`. Thanks to the previous couple of commits, many uses of the `GenKill` trait can be replaced with a concrete type. --- compiler/rustc_borrowck/src/dataflow.rs | 8 +++++-- .../rustc_mir_dataflow/src/framework/mod.rs | 4 ++-- .../src/impls/initialized.rs | 14 +++++------ .../rustc_mir_dataflow/src/impls/liveness.rs | 24 +++++++------------ .../src/impls/storage_liveness.rs | 17 ++++++------- 5 files changed, 33 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index b0f5f638e6764..bef7ad02113d9 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -427,7 +427,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { /// That means they went out of a nonlexical scope fn kill_loans_out_of_scope_at_location( &self, - trans: &mut impl GenKill, + trans: &mut >::Domain, location: Location, ) { // NOTE: The state associated with a given `location` @@ -447,7 +447,11 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { } /// Kill any borrows that conflict with `place`. - fn kill_borrows_on_place(&self, trans: &mut impl GenKill, place: Place<'tcx>) { + fn kill_borrows_on_place( + &self, + trans: &mut >::Domain, + place: Place<'tcx>, + ) { debug!("kill_borrows_on_place: place={:?}", place); let other_borrows_of_local = self diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 9d79b6f44a684..9e419f3ff9a96 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -305,11 +305,11 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { ); /// See `Analysis::apply_switch_int_edge_effects`. - fn switch_int_edge_effects>( + fn switch_int_edge_effects( &mut self, _block: BasicBlock, _discr: &mir::Operand<'tcx>, - _edge_effects: &mut impl SwitchIntEdgeEffects, + _edge_effects: &mut impl SwitchIntEdgeEffects, ) { } } diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index bb61e7e94320e..e5bcb64d6415b 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -270,7 +270,7 @@ impl<'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'_, 'tcx> { impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { fn update_bits( - trans: &mut impl GenKill, + trans: &mut >::Domain, path: MovePathIndex, state: DropFlagState, ) { @@ -283,7 +283,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> { fn update_bits( - trans: &mut impl GenKill, + trans: &mut >::Domain, path: MovePathIndex, state: DropFlagState, ) { @@ -296,7 +296,7 @@ impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> { impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { fn update_bits( - trans: &mut impl GenKill, + trans: &mut >::Domain, path: MovePathIndex, state: DropFlagState, ) { @@ -399,11 +399,11 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { }); } - fn switch_int_edge_effects>( + fn switch_int_edge_effects( &mut self, block: mir::BasicBlock, discr: &mir::Operand<'tcx>, - edge_effects: &mut impl SwitchIntEdgeEffects, + edge_effects: &mut impl SwitchIntEdgeEffects, ) { if !self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration { return; @@ -524,11 +524,11 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { }); } - fn switch_int_edge_effects>( + fn switch_int_edge_effects( &mut self, block: mir::BasicBlock, discr: &mir::Operand<'tcx>, - edge_effects: &mut impl SwitchIntEdgeEffects, + edge_effects: &mut impl SwitchIntEdgeEffects, ) { if !self.tcx.sess.opts.unstable_opts.precise_enum_drop_elaboration { return; diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index af46d5543ba43..07ecedeac593e 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -89,12 +89,9 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { } } -pub struct TransferFunction<'a, T>(pub &'a mut T); +pub struct TransferFunction<'a>(pub &'a mut BitSet); -impl<'tcx, T> Visitor<'tcx> for TransferFunction<'_, T> -where - T: GenKill, -{ +impl<'tcx> Visitor<'tcx> for TransferFunction<'_> { fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) { if let PlaceContext::MutatingUse(MutatingUseContext::Yield) = context { // The resume place is evaluated and assigned to only after coroutine resumes, so its @@ -108,10 +105,10 @@ where MutatingUseContext::Call | MutatingUseContext::AsmOutput, ) = context { - // For the associated terminators, this is only a `Def` when the terminator returns - // "successfully." As such, we handle this case separately in `call_return_effect` - // above. However, if the place looks like `*_5`, this is still unconditionally a use of - // `_5`. + // For the associated terminators, this is only a `Def` when the terminator + // returns "successfully." As such, we handle this case separately in + // `call_return_effect` above. However, if the place looks like `*_5`, this is + // still unconditionally a use of `_5`. } else { self.0.kill(place.local); } @@ -128,12 +125,9 @@ where } } -struct YieldResumeEffect<'a, T>(&'a mut T); +struct YieldResumeEffect<'a>(&'a mut BitSet); -impl<'tcx, T> Visitor<'tcx> for YieldResumeEffect<'_, T> -where - T: GenKill, -{ +impl<'tcx> Visitor<'tcx> for YieldResumeEffect<'_> { fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) { DefUse::apply(self.0, *place, context); self.visit_projection(place.as_ref(), context, location); @@ -151,7 +145,7 @@ enum DefUse { } impl DefUse { - fn apply(trans: &mut impl GenKill, place: Place<'_>, context: PlaceContext) { + fn apply(trans: &mut BitSet, place: Place<'_>, context: PlaceContext) { match DefUse::for_place(place, context) { Some(DefUse::Def) => trans.kill(place.local), Some(DefUse::Use) => trans.gen_(place.local), diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 833cb968e3600..0f94defb1abb9 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -5,7 +5,7 @@ use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use super::MaybeBorrowedLocals; -use crate::{GenKill, ResultsCursor}; +use crate::{AnalysisDomain, GenKill, ResultsCursor}; pub struct MaybeStorageLive<'a> { always_live_locals: Cow<'a, BitSet>, @@ -330,22 +330,23 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { impl<'tcx> MaybeRequiresStorage<'_, 'tcx> { /// Kill locals that are fully moved and have not been borrowed. - fn check_for_move(&mut self, trans: &mut impl GenKill, loc: Location) { + fn check_for_move( + &mut self, + trans: &mut >::Domain, + loc: Location, + ) { let body = self.borrowed_locals.body(); let mut visitor = MoveVisitor { trans, borrowed_locals: &mut self.borrowed_locals }; visitor.visit_location(body, loc); } } -struct MoveVisitor<'a, 'mir, 'tcx, T> { +struct MoveVisitor<'a, 'mir, 'tcx> { borrowed_locals: &'a mut BorrowedLocalsResults<'mir, 'tcx>, - trans: &'a mut T, + trans: &'a mut BitSet, } -impl<'tcx, T> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx, T> -where - T: GenKill, -{ +impl<'tcx> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx> { fn visit_local(&mut self, local: Local, context: PlaceContext, loc: Location) { if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context { self.borrowed_locals.seek_before_primary_effect(loc); From 4dc1b4d0b1c0e96102f6d9b3a0ea91e46feaf8e9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 10 Oct 2024 09:49:33 +1100 Subject: [PATCH 5/7] Remove `GenKillAnalysis`. It's now functionally identical to `Analysis`. --- compiler/rustc_borrowck/src/dataflow.rs | 18 +- .../rustc_mir_dataflow/src/framework/mod.rs | 159 ++---------------- .../src/impls/borrowed_locals.rs | 16 +- .../src/impls/initialized.rs | 62 +++---- .../rustc_mir_dataflow/src/impls/liveness.rs | 16 +- .../src/impls/storage_liveness.rs | 71 ++++---- compiler/rustc_mir_dataflow/src/lib.rs | 6 +- 7 files changed, 82 insertions(+), 266 deletions(-) diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index bef7ad02113d9..2eef200e24c89 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -513,14 +513,8 @@ impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { /// region stops containing the CFG points reachable from the issuing location. /// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of /// `a.b.c` when `a` is overwritten. -impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { - type Idx = BorrowIndex; - - fn domain_size(&self, _: &mir::Body<'tcx>) -> usize { - self.borrow_set.len() - } - - fn before_statement_effect( +impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { + fn apply_before_statement_effect( &mut self, trans: &mut Self::Domain, _statement: &mir::Statement<'tcx>, @@ -529,7 +523,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { self.kill_loans_out_of_scope_at_location(trans, location); } - fn statement_effect( + fn apply_statement_effect( &mut self, trans: &mut Self::Domain, stmt: &mir::Statement<'tcx>, @@ -577,7 +571,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { } } - fn before_terminator_effect( + fn apply_before_terminator_effect( &mut self, trans: &mut Self::Domain, _terminator: &mir::Terminator<'tcx>, @@ -586,7 +580,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { self.kill_loans_out_of_scope_at_location(trans, location); } - fn terminator_effect<'mir>( + fn apply_terminator_effect<'mir>( &mut self, trans: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, @@ -604,7 +598,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { terminator.edges() } - fn call_return_effect( + fn apply_call_return_effect( &mut self, _trans: &mut Self::Domain, _block: mir::BasicBlock, diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 9e419f3ff9a96..d7a62ecd2c181 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -1,9 +1,11 @@ //! A framework that can express both [gen-kill] and generic dataflow problems. //! -//! To use this framework, implement either the [`Analysis`] or the -//! [`GenKillAnalysis`] trait. If your transfer function can be expressed with only gen/kill -//! operations, prefer `GenKillAnalysis` since it will run faster while iterating to fixpoint. The -//! `impls` module contains several examples of gen/kill dataflow analyses. +//! To use this framework, implement the [`Analysis`] trait. There used to be a `GenKillAnalysis` +//! alternative trait for gen-kill analyses that would pre-compute the transfer function for each +//! block. It was intended as an optimization, but it ended up not being any faster than +//! `Analysis`. +//! +//! The `impls` module contains several examples of dataflow analyses. //! //! Create an `Engine` for your analysis using the `into_engine` method on the `Analysis` trait, //! then call `iterate_to_fixpoint`. From there, you can use a `ResultsCursor` to inspect the @@ -122,9 +124,9 @@ pub trait AnalysisDomain<'tcx> { /// /// # Convergence /// -/// When implementing this trait directly (not via [`GenKillAnalysis`]), 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: +/// 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 @@ -223,9 +225,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// Creates an `Engine` to find the fixpoint for this dataflow problem. /// - /// You shouldn't need to override this outside this module, since the combination of the - /// default impl and the one for all `A: GenKillAnalysis` will do the right thing. - /// Its purpose is to enable method chaining like so: + /// You shouldn't need to override this. Its purpose is to enable method chaining like so: /// /// ```ignore (cross-crate-imports) /// let results = MyAnalysis::new(tcx, body) @@ -246,146 +246,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { } } -/// A gen/kill dataflow problem. -/// -/// Each method in this trait has a corresponding one in `Analysis`. However, the first two methods -/// here only allow modification of the dataflow state via "gen" and "kill" operations. By defining -/// transfer functions for each statement in this way, the transfer function for an entire basic -/// block can be computed efficiently. The remaining methods match up with `Analysis` exactly. -/// -/// `Analysis` is automatically implemented for all implementers of `GenKillAnalysis` via a blanket -/// impl below. -pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { - type Idx: Idx; - - fn domain_size(&self, body: &mir::Body<'tcx>) -> usize; - - /// See `Analysis::apply_statement_effect`. - fn statement_effect( - &mut self, - trans: &mut Self::Domain, - statement: &mir::Statement<'tcx>, - location: Location, - ); - - /// See `Analysis::apply_before_statement_effect`. - fn before_statement_effect( - &mut self, - _trans: &mut Self::Domain, - _statement: &mir::Statement<'tcx>, - _location: Location, - ) { - } - - /// See `Analysis::apply_terminator_effect`. - fn terminator_effect<'mir>( - &mut self, - trans: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, - location: Location, - ) -> TerminatorEdges<'mir, 'tcx>; - - /// See `Analysis::apply_before_terminator_effect`. - fn before_terminator_effect( - &mut self, - _trans: &mut Self::Domain, - _terminator: &mir::Terminator<'tcx>, - _location: Location, - ) { - } - - /* Edge-specific effects */ - - /// See `Analysis::apply_call_return_effect`. - fn call_return_effect( - &mut self, - trans: &mut Self::Domain, - block: BasicBlock, - return_places: CallReturnPlaces<'_, 'tcx>, - ); - - /// See `Analysis::apply_switch_int_edge_effects`. - fn switch_int_edge_effects( - &mut self, - _block: BasicBlock, - _discr: &mir::Operand<'tcx>, - _edge_effects: &mut impl SwitchIntEdgeEffects, - ) { - } -} - -// Blanket impl: any impl of `GenKillAnalysis` automatically impls `Analysis`. -impl<'tcx, A> Analysis<'tcx> for A -where - A: GenKillAnalysis<'tcx>, - A::Domain: GenKill + BitSetExt, -{ - fn apply_statement_effect( - &mut self, - state: &mut A::Domain, - statement: &mir::Statement<'tcx>, - location: Location, - ) { - self.statement_effect(state, statement, location); - } - - fn apply_before_statement_effect( - &mut self, - state: &mut A::Domain, - statement: &mir::Statement<'tcx>, - location: Location, - ) { - self.before_statement_effect(state, statement, location); - } - - fn apply_terminator_effect<'mir>( - &mut self, - state: &mut A::Domain, - terminator: &'mir mir::Terminator<'tcx>, - location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { - self.terminator_effect(state, terminator, location) - } - - fn apply_before_terminator_effect( - &mut self, - state: &mut A::Domain, - terminator: &mir::Terminator<'tcx>, - location: Location, - ) { - self.before_terminator_effect(state, terminator, location); - } - - /* Edge-specific effects */ - - fn apply_call_return_effect( - &mut self, - state: &mut A::Domain, - block: BasicBlock, - return_places: CallReturnPlaces<'_, 'tcx>, - ) { - self.call_return_effect(state, block, return_places); - } - - fn apply_switch_int_edge_effects( - &mut self, - block: BasicBlock, - discr: &mir::Operand<'tcx>, - edge_effects: &mut impl SwitchIntEdgeEffects, - ) { - self.switch_int_edge_effects(block, discr, edge_effects); - } -} - /// The legal operations for a transfer function in a gen/kill problem. -/// -/// This abstraction exists because there are two different contexts in which we call the methods in -/// `GenKillAnalysis`. Sometimes we need to store a single transfer function that can be efficiently -/// applied multiple times, such as when computing the cumulative transfer function for each block. -/// These cases require a `GenKillSet`, which in turn requires two `BitSet`s of storage. Oftentimes, -/// however, we only need to apply an effect once. In *these* cases, it is more efficient to pass the -/// `BitSet` representing the state vector directly into the `*_effect` methods as opposed to -/// building up a `GenKillSet` and then throwing it away. pub trait GenKill { /// Inserts `elem` into the state vector. fn gen_(&mut self, elem: T); diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index dc9a1d5f3ad9a..f4edbaf056ce6 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -2,7 +2,7 @@ use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; -use crate::{AnalysisDomain, GenKill, GenKillAnalysis}; +use crate::{Analysis, AnalysisDomain, GenKill}; /// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points /// to a given local. This analysis ignores fake borrows, so it should not be used by @@ -34,14 +34,8 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeBorrowedLocals { } } -impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals { - type Idx = Local; - - fn domain_size(&self, body: &Body<'tcx>) -> usize { - body.local_decls.len() - } - - fn statement_effect( +impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals { + fn apply_statement_effect( &mut self, trans: &mut Self::Domain, statement: &Statement<'tcx>, @@ -50,7 +44,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals { self.transfer_function(trans).visit_statement(statement, location); } - fn terminator_effect<'mir>( + fn apply_terminator_effect<'mir>( &mut self, trans: &mut Self::Domain, terminator: &'mir Terminator<'tcx>, @@ -60,7 +54,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals { terminator.edges() } - fn call_return_effect( + fn apply_call_return_effect( &mut self, _trans: &mut Self::Domain, _block: BasicBlock, diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index e5bcb64d6415b..18a5ca3f6be50 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -11,7 +11,7 @@ use crate::elaborate_drops::DropFlagState; use crate::framework::SwitchIntEdgeEffects; use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex}; use crate::{ - AnalysisDomain, GenKill, GenKillAnalysis, MaybeReachable, drop_flag_effects, + Analysis, AnalysisDomain, GenKill, MaybeReachable, drop_flag_effects, drop_flag_effects_for_function_entry, drop_flag_effects_for_location, lattice, on_all_children_bits, on_lookup_result_bits, }; @@ -329,14 +329,8 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } } -impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { - type Idx = MovePathIndex; - - fn domain_size(&self, _: &Body<'tcx>) -> usize { - self.move_data().move_paths.len() - } - - fn statement_effect( +impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { + fn apply_statement_effect( &mut self, trans: &mut Self::Domain, statement: &mir::Statement<'tcx>, @@ -360,7 +354,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } } - fn terminator_effect<'mir>( + fn apply_terminator_effect<'mir>( &mut self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, @@ -380,7 +374,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { edges } - fn call_return_effect( + fn apply_call_return_effect( &mut self, trans: &mut Self::Domain, _block: mir::BasicBlock, @@ -399,7 +393,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { }); } - fn switch_int_edge_effects( + fn apply_switch_int_edge_effects( &mut self, block: mir::BasicBlock, discr: &mir::Operand<'tcx>, @@ -466,14 +460,8 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } } -impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { - type Idx = MovePathIndex; - - fn domain_size(&self, _: &Body<'tcx>) -> usize { - self.move_data().move_paths.len() - } - - fn statement_effect( +impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { + fn apply_statement_effect( &mut self, trans: &mut Self::Domain, _statement: &mir::Statement<'tcx>, @@ -487,7 +475,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { // mutable borrow occurs. Places cannot become uninitialized through a mutable reference. } - fn terminator_effect<'mir>( + fn apply_terminator_effect<'mir>( &mut self, trans: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, @@ -505,7 +493,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } } - fn call_return_effect( + fn apply_call_return_effect( &mut self, trans: &mut Self::Domain, _block: mir::BasicBlock, @@ -524,7 +512,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { }); } - fn switch_int_edge_effects( + fn apply_switch_int_edge_effects( &mut self, block: mir::BasicBlock, discr: &mir::Operand<'tcx>, @@ -593,14 +581,8 @@ impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { } } -impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { - type Idx = MovePathIndex; - - fn domain_size(&self, _: &Body<'tcx>) -> usize { - self.move_data().move_paths.len() - } - - fn statement_effect( +impl<'tcx> Analysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { + fn apply_statement_effect( &mut self, trans: &mut Self::Domain, _statement: &mir::Statement<'tcx>, @@ -611,7 +593,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { }) } - fn terminator_effect<'mir>( + fn apply_terminator_effect<'mir>( &mut self, trans: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, @@ -623,7 +605,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { terminator.edges() } - fn call_return_effect( + fn apply_call_return_effect( &mut self, trans: &mut Self::Domain, _block: mir::BasicBlock, @@ -662,15 +644,9 @@ impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { } } -impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { - type Idx = InitIndex; - - fn domain_size(&self, _: &Body<'tcx>) -> usize { - self.move_data().inits.len() - } - +impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { #[instrument(skip(self, trans), level = "debug")] - fn statement_effect( + fn apply_statement_effect( &mut self, trans: &mut Self::Domain, stmt: &mir::Statement<'tcx>, @@ -698,7 +674,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { } #[instrument(skip(self, trans, terminator), level = "debug")] - fn terminator_effect<'mir>( + fn apply_terminator_effect<'mir>( &mut self, trans: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, @@ -720,7 +696,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { terminator.edges() } - fn call_return_effect( + fn apply_call_return_effect( &mut self, trans: &mut Self::Domain, block: mir::BasicBlock, diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 07ecedeac593e..452fae379be60 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -4,7 +4,7 @@ use rustc_middle::mir::{ self, CallReturnPlaces, Local, Location, Place, StatementKind, TerminatorEdges, }; -use crate::{Analysis, AnalysisDomain, Backward, GenKill, GenKillAnalysis}; +use crate::{Analysis, AnalysisDomain, Backward, GenKill}; /// A [live-variable dataflow analysis][liveness]. /// @@ -41,14 +41,8 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeLiveLocals { } } -impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { - type Idx = Local; - - fn domain_size(&self, body: &mir::Body<'tcx>) -> usize { - body.local_decls.len() - } - - fn statement_effect( +impl<'tcx> Analysis<'tcx> for MaybeLiveLocals { + fn apply_statement_effect( &mut self, trans: &mut Self::Domain, statement: &mir::Statement<'tcx>, @@ -57,7 +51,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { TransferFunction(trans).visit_statement(statement, location); } - fn terminator_effect<'mir>( + fn apply_terminator_effect<'mir>( &mut self, trans: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, @@ -67,7 +61,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals { terminator.edges() } - fn call_return_effect( + fn apply_call_return_effect( &mut self, trans: &mut Self::Domain, _block: mir::BasicBlock, diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 0f94defb1abb9..6ccd7dc17a22c 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -5,7 +5,7 @@ use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use super::MaybeBorrowedLocals; -use crate::{AnalysisDomain, GenKill, ResultsCursor}; +use crate::{Analysis, AnalysisDomain, GenKill, ResultsCursor}; pub struct MaybeStorageLive<'a> { always_live_locals: Cow<'a, BitSet>, @@ -17,7 +17,7 @@ impl<'a> MaybeStorageLive<'a> { } } -impl<'a, 'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> { +impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeStorageLive<'a> { type Domain = BitSet; const NAME: &'static str = "maybe_storage_live"; @@ -39,14 +39,13 @@ impl<'a, 'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> { } } -impl<'a, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { - type Idx = Local; - - fn domain_size(&self, body: &Body<'tcx>) -> usize { - body.local_decls.len() - } - - fn statement_effect(&mut self, trans: &mut Self::Domain, stmt: &Statement<'tcx>, _: Location) { +impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageLive<'a> { + fn apply_statement_effect( + &mut self, + trans: &mut Self::Domain, + stmt: &Statement<'tcx>, + _: Location, + ) { match stmt.kind { StatementKind::StorageLive(l) => trans.gen_(l), StatementKind::StorageDead(l) => trans.kill(l), @@ -54,7 +53,7 @@ impl<'a, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { } } - fn terminator_effect<'mir>( + fn apply_terminator_effect<'mir>( &mut self, _trans: &mut Self::Domain, terminator: &'mir Terminator<'tcx>, @@ -64,7 +63,7 @@ impl<'a, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> { terminator.edges() } - fn call_return_effect( + fn apply_call_return_effect( &mut self, _trans: &mut Self::Domain, _block: BasicBlock, @@ -84,7 +83,7 @@ impl<'a> MaybeStorageDead<'a> { } } -impl<'a, 'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageDead<'a> { +impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeStorageDead<'a> { type Domain = BitSet; const NAME: &'static str = "maybe_storage_dead"; @@ -105,14 +104,13 @@ impl<'a, 'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageDead<'a> { } } -impl<'a, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead<'a> { - type Idx = Local; - - fn domain_size(&self, body: &Body<'tcx>) -> usize { - body.local_decls.len() - } - - fn statement_effect(&mut self, trans: &mut Self::Domain, stmt: &Statement<'tcx>, _: Location) { +impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageDead<'a> { + fn apply_statement_effect( + &mut self, + trans: &mut Self::Domain, + stmt: &Statement<'tcx>, + _: Location, + ) { match stmt.kind { StatementKind::StorageLive(l) => trans.kill(l), StatementKind::StorageDead(l) => trans.gen_(l), @@ -120,7 +118,7 @@ impl<'a, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead<'a> { } } - fn terminator_effect<'mir>( + fn apply_terminator_effect<'mir>( &mut self, _: &mut Self::Domain, terminator: &'mir Terminator<'tcx>, @@ -130,7 +128,7 @@ impl<'a, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead<'a> { terminator.edges() } - fn call_return_effect( + fn apply_call_return_effect( &mut self, _trans: &mut Self::Domain, _block: BasicBlock, @@ -154,7 +152,7 @@ impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { } } -impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'_, 'tcx> { +impl<'tcx> AnalysisDomain<'tcx> for MaybeRequiresStorage<'_, 'tcx> { type Domain = BitSet; const NAME: &'static str = "requires_storage"; @@ -173,21 +171,15 @@ impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'_, 'tcx> { } } -impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { - type Idx = Local; - - fn domain_size(&self, body: &Body<'tcx>) -> usize { - body.local_decls.len() - } - - fn before_statement_effect( +impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { + fn apply_before_statement_effect( &mut self, trans: &mut Self::Domain, stmt: &Statement<'tcx>, loc: Location, ) { // If a place is borrowed in a statement, it needs storage for that statement. - self.borrowed_locals.mut_analysis().statement_effect(trans, stmt, loc); + self.borrowed_locals.mut_analysis().apply_statement_effect(trans, stmt, loc); match &stmt.kind { StatementKind::StorageDead(l) => trans.kill(*l), @@ -213,13 +205,18 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { } } - fn statement_effect(&mut self, trans: &mut Self::Domain, _: &Statement<'tcx>, loc: Location) { + fn apply_statement_effect( + &mut self, + trans: &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); } - fn before_terminator_effect( + fn apply_before_terminator_effect( &mut self, trans: &mut Self::Domain, terminator: &Terminator<'tcx>, @@ -277,7 +274,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { } } - fn terminator_effect<'t>( + fn apply_terminator_effect<'t>( &mut self, trans: &mut Self::Domain, terminator: &'t Terminator<'tcx>, @@ -318,7 +315,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { terminator.edges() } - fn call_return_effect( + fn apply_call_return_effect( &mut self, trans: &mut Self::Domain, _block: BasicBlock, diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index cd926c0764129..d07928dcdc99c 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -18,9 +18,9 @@ pub use self::drop_flag_effects::{ move_path_children_matching, on_all_children_bits, on_lookup_result_bits, }; pub use self::framework::{ - Analysis, AnalysisDomain, Backward, Direction, Engine, Forward, GenKill, GenKillAnalysis, - JoinSemiLattice, MaybeReachable, Results, ResultsCursor, ResultsVisitable, ResultsVisitor, - SwitchIntEdgeEffects, fmt, graphviz, lattice, visit_results, + Analysis, AnalysisDomain, Backward, Direction, Engine, Forward, GenKill, JoinSemiLattice, + MaybeReachable, Results, ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, + fmt, graphviz, lattice, visit_results, }; use self::move_paths::MoveData; From ba13775319fa51933da6e90053a9f96778b15b6b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 10 Oct 2024 11:46:29 +1100 Subject: [PATCH 6/7] Merge `AnalysisDomain` into `Analysis`. With `GenKillAnalysis` gone, there is no need for them to be separate. --- compiler/rustc_borrowck/src/dataflow.rs | 30 +++++++------- .../src/check_consts/resolver.rs | 9 +--- .../src/framework/engine.rs | 5 +-- .../rustc_mir_dataflow/src/framework/mod.rs | 41 +++++++++---------- .../rustc_mir_dataflow/src/framework/tests.rs | 4 +- .../src/impls/borrowed_locals.rs | 6 +-- .../src/impls/initialized.rs | 27 ++++-------- .../rustc_mir_dataflow/src/impls/liveness.rs | 10 ++--- .../src/impls/storage_liveness.rs | 20 +++------ compiler/rustc_mir_dataflow/src/lib.rs | 6 +-- .../rustc_mir_dataflow/src/value_analysis.rs | 9 +--- 11 files changed, 62 insertions(+), 105 deletions(-) diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 2eef200e24c89..216cf8ac98886 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -7,7 +7,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces}; -use rustc_mir_dataflow::{Analysis, AnalysisDomain, Forward, GenKill, Results, ResultsVisitable}; +use rustc_mir_dataflow::{Analysis, Forward, GenKill, Results, ResultsVisitable}; use tracing::debug; use crate::{BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, places_conflict}; @@ -22,9 +22,9 @@ pub(crate) struct BorrowckResults<'a, 'tcx> { /// The transient state of the dataflow analyses used by the borrow checker. #[derive(Debug)] pub(crate) struct BorrowckDomain<'a, 'tcx> { - pub(crate) borrows: as AnalysisDomain<'tcx>>::Domain, - pub(crate) uninits: as AnalysisDomain<'tcx>>::Domain, - pub(crate) ever_inits: as AnalysisDomain<'tcx>>::Domain, + pub(crate) borrows: as Analysis<'tcx>>::Domain, + pub(crate) uninits: as Analysis<'tcx>>::Domain, + pub(crate) ever_inits: as Analysis<'tcx>>::Domain, } impl<'a, 'tcx> ResultsVisitable<'tcx> for BorrowckResults<'a, 'tcx> { @@ -427,7 +427,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { /// That means they went out of a nonlexical scope fn kill_loans_out_of_scope_at_location( &self, - trans: &mut >::Domain, + trans: &mut >::Domain, location: Location, ) { // NOTE: The state associated with a given `location` @@ -449,7 +449,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { /// Kill any borrows that conflict with `place`. fn kill_borrows_on_place( &self, - trans: &mut >::Domain, + trans: &mut >::Domain, place: Place<'tcx>, ) { debug!("kill_borrows_on_place: place={:?}", place); @@ -490,7 +490,14 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { } } -impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { +/// Forward dataflow computation of the set of borrows that are in scope at a particular location. +/// - we gen the introduced loans +/// - we kill loans on locals going out of (regular) scope +/// - we kill the loans going out of their region's NLL scope: in NLL terms, the frontier where a +/// region stops containing the CFG points reachable from the issuing location. +/// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of +/// `a.b.c` when `a` is overwritten. +impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { type Domain = BitSet; const NAME: &'static str = "borrows"; @@ -504,16 +511,7 @@ impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { // no borrows of code region_scopes have been taken prior to // function execution, so this method has no effect. } -} -/// Forward dataflow computation of the set of borrows that are in scope at a particular location. -/// - we gen the introduced loans -/// - we kill loans on locals going out of (regular) scope -/// - we kill the loans going out of their region's NLL scope: in NLL terms, the frontier where a -/// region stops containing the CFG points reachable from the issuing location. -/// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of -/// `a.b.c` when `a` is overwritten. -impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { fn apply_before_statement_effect( &mut self, trans: &mut Self::Domain, diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index eb5024c36f4b6..74eb6b37fbbad 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::{ self, BasicBlock, CallReturnPlaces, Local, Location, Statement, StatementKind, TerminatorEdges, }; use rustc_mir_dataflow::fmt::DebugWithContext; -use rustc_mir_dataflow::{Analysis, AnalysisDomain, JoinSemiLattice}; +use rustc_mir_dataflow::{Analysis, JoinSemiLattice}; use super::{ConstCx, Qualif, qualifs}; @@ -310,7 +310,7 @@ impl JoinSemiLattice for State { } } -impl<'tcx, Q> AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q> +impl<'tcx, Q> Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q> where Q: Qualif, { @@ -328,12 +328,7 @@ where fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut Self::Domain) { self.transfer_function(state).initialize_state(); } -} -impl<'tcx, Q> Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q> -where - Q: Qualif, -{ fn apply_statement_effect( &mut self, state: &mut Self::Domain, diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index d6853b6ef829f..cbd1083d037d2 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -16,14 +16,13 @@ use {rustc_ast as ast, rustc_graphviz as dot}; use super::fmt::DebugWithContext; use super::{ - Analysis, AnalysisDomain, Direction, JoinSemiLattice, ResultsCursor, ResultsVisitor, graphviz, - visit_results, + Analysis, Direction, JoinSemiLattice, ResultsCursor, ResultsVisitor, graphviz, visit_results, }; use crate::errors::{ DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter, }; -type EntrySets<'tcx, A> = IndexVec>::Domain>; +type EntrySets<'tcx, A> = IndexVec>::Domain>; /// A dataflow analysis that has converged to fixpoint. #[derive(Clone)] diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index d7a62ecd2c181..4e72ffabc6e06 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -89,11 +89,26 @@ impl BitSetExt for ChunkedBitSet { } } -/// Defines the domain of a dataflow problem. +/// 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. /// -/// This trait specifies the lattice on which this analysis operates (the domain) as well as its -/// initial value at the entry point of each basic block. -pub trait AnalysisDomain<'tcx> { +/// # 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. +pub trait Analysis<'tcx> { /// The type that holds the dataflow state at any given point in the program. type Domain: Clone + JoinSemiLattice; @@ -118,25 +133,7 @@ pub trait AnalysisDomain<'tcx> { // block where control flow could exit the MIR body (e.g., those terminated with `return` or // `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); -} -/// A dataflow problem with an arbitrarily complex transfer function. -/// -/// # 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. -pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// Updates the current dataflow state with the effect of evaluating a statement. fn apply_statement_effect( &mut self, diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 1861f4cffc717..de171dbc3138b 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -154,7 +154,7 @@ impl MockAnalysis<'_, D> { } } -impl<'tcx, D: Direction> AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> { +impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> { type Domain = BitSet; type Direction = D; @@ -167,9 +167,7 @@ impl<'tcx, D: Direction> AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> { fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { unimplemented!("This is never called since `MockAnalysis` is never iterated to fixpoint"); } -} -impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> { fn apply_statement_effect( &mut self, state: &mut Self::Domain, diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index f4edbaf056ce6..56c38cb02f92f 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -2,7 +2,7 @@ use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; -use crate::{Analysis, AnalysisDomain, GenKill}; +use crate::{Analysis, GenKill}; /// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points /// to a given local. This analysis ignores fake borrows, so it should not be used by @@ -20,7 +20,7 @@ impl MaybeBorrowedLocals { } } -impl<'tcx> AnalysisDomain<'tcx> for MaybeBorrowedLocals { +impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals { type Domain = BitSet; const NAME: &'static str = "maybe_borrowed_locals"; @@ -32,9 +32,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeBorrowedLocals { fn initialize_start_block(&self, _: &Body<'tcx>, _: &mut Self::Domain) { // No locals are aliased on function entry } -} -impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals { fn apply_statement_effect( &mut self, trans: &mut Self::Domain, diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 18a5ca3f6be50..9bb50d1e056bd 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -11,9 +11,8 @@ use crate::elaborate_drops::DropFlagState; use crate::framework::SwitchIntEdgeEffects; use crate::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex}; use crate::{ - Analysis, AnalysisDomain, GenKill, MaybeReachable, drop_flag_effects, - drop_flag_effects_for_function_entry, drop_flag_effects_for_location, lattice, - on_all_children_bits, on_lookup_result_bits, + Analysis, GenKill, MaybeReachable, drop_flag_effects, drop_flag_effects_for_function_entry, + drop_flag_effects_for_location, lattice, on_all_children_bits, on_lookup_result_bits, }; /// `MaybeInitializedPlaces` tracks all places that might be @@ -270,7 +269,7 @@ impl<'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'_, 'tcx> { impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { fn update_bits( - trans: &mut >::Domain, + trans: &mut >::Domain, path: MovePathIndex, state: DropFlagState, ) { @@ -283,7 +282,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> { fn update_bits( - trans: &mut >::Domain, + trans: &mut >::Domain, path: MovePathIndex, state: DropFlagState, ) { @@ -296,7 +295,7 @@ impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> { impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { fn update_bits( - trans: &mut >::Domain, + trans: &mut >::Domain, path: MovePathIndex, state: DropFlagState, ) { @@ -307,7 +306,7 @@ impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { } } -impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { +impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { /// There can be many more `MovePathIndex` than there are locals in a MIR body. /// We use a chunked bitset to avoid paying too high a memory footprint. type Domain = MaybeReachable>; @@ -327,9 +326,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { state.gen_(path); }); } -} -impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { fn apply_statement_effect( &mut self, trans: &mut Self::Domain, @@ -436,7 +433,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } } -impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { +impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { /// There can be many more `MovePathIndex` than there are locals in a MIR body. /// We use a chunked bitset to avoid paying too high a memory footprint. type Domain = ChunkedBitSet; @@ -458,9 +455,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { state.remove(path); }); } -} -impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { fn apply_statement_effect( &mut self, trans: &mut Self::Domain, @@ -559,7 +554,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } } -impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { +impl<'a, 'tcx> Analysis<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { /// Use set intersection as the join operator. type Domain = lattice::Dual>; @@ -579,9 +574,7 @@ impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { state.0.insert(path); }); } -} -impl<'tcx> Analysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { fn apply_statement_effect( &mut self, trans: &mut Self::Domain, @@ -625,7 +618,7 @@ impl<'tcx> Analysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { } } -impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { +impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { /// There can be many more `InitIndex` than there are locals in a MIR body. /// We use a chunked bitset to avoid paying too high a memory footprint. type Domain = ChunkedBitSet; @@ -642,9 +635,7 @@ impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { state.insert(InitIndex::new(arg_init)); } } -} -impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { #[instrument(skip(self, trans), level = "debug")] fn apply_statement_effect( &mut self, diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 452fae379be60..e06c1f2bb49e3 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -4,7 +4,7 @@ use rustc_middle::mir::{ self, CallReturnPlaces, Local, Location, Place, StatementKind, TerminatorEdges, }; -use crate::{Analysis, AnalysisDomain, Backward, GenKill}; +use crate::{Analysis, Backward, GenKill}; /// A [live-variable dataflow analysis][liveness]. /// @@ -25,7 +25,7 @@ use crate::{Analysis, AnalysisDomain, Backward, GenKill}; /// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis pub struct MaybeLiveLocals; -impl<'tcx> AnalysisDomain<'tcx> for MaybeLiveLocals { +impl<'tcx> Analysis<'tcx> for MaybeLiveLocals { type Domain = BitSet; type Direction = Backward; @@ -39,9 +39,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeLiveLocals { fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { // No variables are live until we observe a use } -} -impl<'tcx> Analysis<'tcx> for MaybeLiveLocals { fn apply_statement_effect( &mut self, trans: &mut Self::Domain, @@ -219,7 +217,7 @@ impl<'a> MaybeTransitiveLiveLocals<'a> { } } -impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a> { +impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { type Domain = BitSet; type Direction = Backward; @@ -233,9 +231,7 @@ impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a> { fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { // No variables are live until we observe a use } -} -impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { fn apply_statement_effect( &mut self, trans: &mut Self::Domain, diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 6ccd7dc17a22c..07769057096ea 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -5,7 +5,7 @@ use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use super::MaybeBorrowedLocals; -use crate::{Analysis, AnalysisDomain, GenKill, ResultsCursor}; +use crate::{Analysis, GenKill, ResultsCursor}; pub struct MaybeStorageLive<'a> { always_live_locals: Cow<'a, BitSet>, @@ -17,7 +17,7 @@ impl<'a> MaybeStorageLive<'a> { } } -impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeStorageLive<'a> { +impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageLive<'a> { type Domain = BitSet; const NAME: &'static str = "maybe_storage_live"; @@ -37,9 +37,7 @@ impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeStorageLive<'a> { on_entry.insert(arg); } } -} -impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageLive<'a> { fn apply_statement_effect( &mut self, trans: &mut Self::Domain, @@ -83,7 +81,7 @@ impl<'a> MaybeStorageDead<'a> { } } -impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeStorageDead<'a> { +impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageDead<'a> { type Domain = BitSet; const NAME: &'static str = "maybe_storage_dead"; @@ -102,9 +100,7 @@ impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeStorageDead<'a> { } } } -} -impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageDead<'a> { fn apply_statement_effect( &mut self, trans: &mut Self::Domain, @@ -152,7 +148,7 @@ impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { } } -impl<'tcx> AnalysisDomain<'tcx> for MaybeRequiresStorage<'_, 'tcx> { +impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { type Domain = BitSet; const NAME: &'static str = "requires_storage"; @@ -169,9 +165,7 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeRequiresStorage<'_, 'tcx> { on_entry.insert(arg); } } -} -impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { fn apply_before_statement_effect( &mut self, trans: &mut Self::Domain, @@ -327,11 +321,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { impl<'tcx> MaybeRequiresStorage<'_, 'tcx> { /// Kill locals that are fully moved and have not been borrowed. - fn check_for_move( - &mut self, - trans: &mut >::Domain, - loc: Location, - ) { + fn check_for_move(&mut self, trans: &mut >::Domain, loc: Location) { let body = self.borrowed_locals.body(); let mut visitor = MoveVisitor { trans, borrowed_locals: &mut self.borrowed_locals }; visitor.visit_location(body, loc); diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index d07928dcdc99c..b284f0308f979 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -18,9 +18,9 @@ pub use self::drop_flag_effects::{ move_path_children_matching, on_all_children_bits, on_lookup_result_bits, }; pub use self::framework::{ - Analysis, AnalysisDomain, Backward, Direction, Engine, Forward, GenKill, JoinSemiLattice, - MaybeReachable, Results, ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, - fmt, graphviz, lattice, visit_results, + Analysis, Backward, Direction, Engine, Forward, GenKill, JoinSemiLattice, MaybeReachable, + Results, ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, + lattice, visit_results, }; use self::move_paths::MoveData; diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index aa09fe1dd45e9..faee40faa3f55 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -51,7 +51,7 @@ use tracing::debug; use crate::fmt::DebugWithContext; use crate::lattice::{HasBottom, HasTop}; -use crate::{Analysis, AnalysisDomain, JoinSemiLattice, SwitchIntEdgeEffects}; +use crate::{Analysis, JoinSemiLattice, SwitchIntEdgeEffects}; pub trait ValueAnalysis<'tcx> { /// For each place of interest, the analysis tracks a value of the given type. @@ -334,7 +334,7 @@ pub trait ValueAnalysis<'tcx> { pub struct ValueAnalysisWrapper(pub T); -impl<'tcx, T: ValueAnalysis<'tcx>> AnalysisDomain<'tcx> for ValueAnalysisWrapper { +impl<'tcx, T: ValueAnalysis<'tcx>> Analysis<'tcx> for ValueAnalysisWrapper { type Domain = State; const NAME: &'static str = T::NAME; @@ -351,12 +351,7 @@ impl<'tcx, T: ValueAnalysis<'tcx>> AnalysisDomain<'tcx> for ValueAnalysisWrapper state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map()); } } -} -impl<'tcx, T> Analysis<'tcx> for ValueAnalysisWrapper -where - T: ValueAnalysis<'tcx>, -{ fn apply_statement_effect( &mut self, state: &mut Self::Domain, From 33abf6a0c8b9a051c06dcb43935f3e15c96ade45 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 10 Oct 2024 12:06:25 +1100 Subject: [PATCH 7/7] Add defaults for `Analysis::apply_{call_return_effect,terminator_effect}`. To avoid some low-value boilerplate code. --- compiler/rustc_borrowck/src/dataflow.rs | 12 +----- .../rustc_mir_dataflow/src/framework/mod.rs | 17 +++++---- .../rustc_mir_dataflow/src/framework/tests.rs | 8 ---- .../src/impls/borrowed_locals.rs | 8 ---- .../src/impls/storage_liveness.rs | 38 ------------------- 5 files changed, 11 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 216cf8ac98886..89ff12c1479ae 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -1,9 +1,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::graph; use rustc_index::bit_set::BitSet; -use rustc_middle::mir::{ - self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges, -}; +use rustc_middle::mir::{self, BasicBlock, Body, Location, Place, TerminatorEdges}; use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces}; @@ -595,14 +593,6 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { } terminator.edges() } - - fn apply_call_return_effect( - &mut self, - _trans: &mut Self::Domain, - _block: mir::BasicBlock, - _return_places: CallReturnPlaces<'_, 'tcx>, - ) { - } } impl DebugWithContext for BorrowIndex {} diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 4e72ffabc6e06..959f1ea534090 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -164,10 +164,12 @@ pub trait Analysis<'tcx> { /// initialized here. fn apply_terminator_effect<'mir>( &mut self, - state: &mut Self::Domain, + _state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, - location: Location, - ) -> TerminatorEdges<'mir, 'tcx>; + _location: Location, + ) -> TerminatorEdges<'mir, 'tcx> { + terminator.edges() + } /// Updates the current dataflow state with an effect that occurs immediately *before* the /// given terminator. @@ -192,10 +194,11 @@ pub trait Analysis<'tcx> { /// edges. fn apply_call_return_effect( &mut self, - state: &mut Self::Domain, - block: BasicBlock, - return_places: CallReturnPlaces<'_, 'tcx>, - ); + _state: &mut Self::Domain, + _block: BasicBlock, + _return_places: CallReturnPlaces<'_, 'tcx>, + ) { + } /// Updates the current dataflow state with the effect of taking a particular branch in a /// `SwitchInt` terminator. diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index de171dbc3138b..14fb6dfb50c80 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -208,14 +208,6 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> { let idx = self.effect(Effect::Before.at_index(location.statement_index)); assert!(state.insert(idx)); } - - fn apply_call_return_effect( - &mut self, - _state: &mut Self::Domain, - _block: BasicBlock, - _return_places: CallReturnPlaces<'_, 'tcx>, - ) { - } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 56c38cb02f92f..859019fd1f6ee 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -51,14 +51,6 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals { self.transfer_function(trans).visit_terminator(terminator, location); terminator.edges() } - - fn apply_call_return_effect( - &mut self, - _trans: &mut Self::Domain, - _block: BasicBlock, - _return_places: CallReturnPlaces<'_, 'tcx>, - ) { - } } /// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`. diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 07769057096ea..c5fd2a631ff74 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -50,25 +50,6 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageLive<'a> { _ => (), } } - - fn apply_terminator_effect<'mir>( - &mut self, - _trans: &mut Self::Domain, - terminator: &'mir Terminator<'tcx>, - _: Location, - ) -> TerminatorEdges<'mir, 'tcx> { - // Terminators have no effect - terminator.edges() - } - - fn apply_call_return_effect( - &mut self, - _trans: &mut Self::Domain, - _block: BasicBlock, - _return_places: CallReturnPlaces<'_, 'tcx>, - ) { - // Nothing to do when a call returns successfully - } } pub struct MaybeStorageDead<'a> { @@ -113,25 +94,6 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageDead<'a> { _ => (), } } - - fn apply_terminator_effect<'mir>( - &mut self, - _: &mut Self::Domain, - terminator: &'mir Terminator<'tcx>, - _: Location, - ) -> TerminatorEdges<'mir, 'tcx> { - // Terminators have no effect - terminator.edges() - } - - fn apply_call_return_effect( - &mut self, - _trans: &mut Self::Domain, - _block: BasicBlock, - _return_places: CallReturnPlaces<'_, 'tcx>, - ) { - // Nothing to do when a call returns successfully - } } type BorrowedLocalsResults<'mir, 'tcx> = ResultsCursor<'mir, 'tcx, MaybeBorrowedLocals>;