diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 5bf692eaa7205..5bfe5ee64f050 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -2,9 +2,7 @@ use std::fmt; use rustc_data_structures::fx::FxIndexMap; use rustc_index::bit_set::{DenseBitSet, MixedBitSet}; -use rustc_middle::mir::{ - self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges, -}; +use rustc_middle::mir::{self, BasicBlock, Body, CallReturnPlaces, Location, Place}; use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::impls::{ @@ -76,19 +74,15 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { self.ever_inits.apply_early_terminator_effect(&mut state.ever_inits, term, loc); } - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - term: &'mir mir::Terminator<'tcx>, + term: &mir::Terminator<'tcx>, loc: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { self.borrows.apply_primary_terminator_effect(&mut state.borrows, term, loc); self.uninits.apply_primary_terminator_effect(&mut state.uninits, term, loc); self.ever_inits.apply_primary_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( @@ -598,12 +592,12 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { self.kill_loans_out_of_scope_at_location(state, location); } - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, + terminator: &mir::Terminator<'tcx>, _location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { if let mir::TerminatorKind::InlineAsm { operands, .. } = &terminator.kind { for op in operands { if let mir::InlineAsmOperand::Out { place: Some(place), .. } @@ -613,7 +607,6 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { } } } - terminator.edges() } } diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index a230f797b56fd..29b6e26d950d5 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -8,7 +8,7 @@ use std::marker::PhantomData; use rustc_index::bit_set::MixedBitSet; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::{ - self, BasicBlock, CallReturnPlaces, Local, Location, Statement, StatementKind, TerminatorEdges, + self, BasicBlock, CallReturnPlaces, Local, Location, Statement, StatementKind, }; use rustc_mir_dataflow::fmt::DebugWithContext; use rustc_mir_dataflow::{Analysis, JoinSemiLattice}; @@ -351,14 +351,13 @@ where self.transfer_function(state).visit_statement(statement, location); } - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, + terminator: &mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { self.transfer_function(state).visit_terminator(terminator, location); - terminator.edges() } fn apply_call_return_effect( diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 68c8e03de8022..7b577c2b9df4c 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -194,7 +194,9 @@ impl Direction for Forward { let terminator = block_data.terminator(); let location = Location { block, statement_index: block_data.statements.len() }; analysis.apply_early_terminator_effect(state, terminator, location); - let edges = analysis.apply_primary_terminator_effect(state, terminator, location); + // Edges are obtained *before* calling `apply_primary_terminator_effect`. + let edges = analysis.get_terminator_edges(state, terminator, location); + analysis.apply_primary_terminator_effect(state, terminator, location); let exit_state = state; match edges { diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 8f58846152747..b767ed6005346 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -196,19 +196,30 @@ pub trait Analysis<'tcx> { ) { } + /// Gets the terminator edges. Used by forward analyses only. Called *before* + /// `apply_primary_terminator_effect` is applied; this might seem strange but in practice + /// `MaybeInitializedPlaces` needs that ordering and other analyses work with either ordering. + fn get_terminator_edges<'mir>( + &self, + _state: &Self::Domain, + terminator: &'mir mir::Terminator<'tcx>, + _location: Location, + ) -> TerminatorEdges<'mir, 'tcx> { + terminator.edges() + } + /// Updates the current dataflow state with the effect of evaluating a terminator. /// /// The effect of a successful return from a `Call` terminator should **not** be accounted for /// in this function. That should go in `apply_call_return_effect`. For example, in the /// `InitializedPlaces` analyses, the return place for a function call is not marked as /// initialized here. - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, _state: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, + _terminator: &mir::Terminator<'tcx>, _location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { - terminator.edges() + ) { } /* Edge-specific effects */ diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 86ea3a34ae0ea..ee6330bfe1c2c 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -197,15 +197,14 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> { assert!(state.insert(idx)); } - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, + _terminator: &mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { let idx = self.effect(Effect::Primary.at_index(location.statement_index)); assert!(state.insert(idx)); - terminator.edges() } } diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 9ec68f5260c05..c5b69c563b2fe 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -41,14 +41,13 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals { Self::transfer_function(state).visit_statement(statement, location); } - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - terminator: &'mir Terminator<'tcx>, + terminator: &Terminator<'tcx>, location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { Self::transfer_function(state).visit_terminator(terminator, location); - terminator.edges() } } diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 543c833326021..1b2c58c7e514c 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -391,14 +391,15 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } } - fn apply_primary_terminator_effect<'mir>( + fn get_terminator_edges<'mir>( &self, - state: &mut Self::Domain, + state: &Self::Domain, terminator: &'mir mir::Terminator<'tcx>, - location: Location, + _location: Location, ) -> TerminatorEdges<'mir, 'tcx> { - // Note: `edges` must be computed first because `drop_flag_effects_for_location` can change - // the result of `is_unwind_dead`. + // Note: this relies on `get_terminator_edges` being called before + // `apply_primary_terminator_effect` because the result of `is_unwind_dead` is affected by + // the `drop_flag_effects_for_location` in `apply_primary_terminator_effect`. let mut edges = terminator.edges(); if self.skip_unreachable_unwind && let mir::TerminatorKind::Drop { target, unwind, place, replace: _, drop: _ } = @@ -408,10 +409,18 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { { edges = TerminatorEdges::Single(target); } + edges + } + + fn apply_primary_terminator_effect( + &self, + state: &mut Self::Domain, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| { Self::update_bits(state, path, s) }); - edges } fn apply_call_return_effect( @@ -514,15 +523,12 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { // mutable borrow occurs. Places cannot become uninitialized through a mutable reference. } - fn apply_primary_terminator_effect<'mir>( + fn get_terminator_edges<'mir>( &self, - state: &mut Self::Domain, + _state: &Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, ) -> TerminatorEdges<'mir, 'tcx> { - drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| { - Self::update_bits(state, path, s) - }); if self.skip_unreachable_unwind.contains(location.block) { let mir::TerminatorKind::Drop { target, unwind, .. } = terminator.kind else { bug!() }; assert_matches!(unwind, mir::UnwindAction::Cleanup(_)); @@ -532,6 +538,17 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } } + fn apply_primary_terminator_effect( + &self, + state: &mut Self::Domain, + _terminator: &mir::Terminator<'tcx>, + location: Location, + ) { + drop_flag_effects_for_location(self.body, self.move_data, location, |path, s| { + Self::update_bits(state, path, s) + }); + } + fn apply_call_return_effect( &self, state: &mut Self::Domain, @@ -633,13 +650,13 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { } } - #[instrument(skip(self, state, terminator), level = "debug")] - fn apply_primary_terminator_effect<'mir>( + #[instrument(skip(self, state, _terminator), level = "debug")] + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, + _terminator: &mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { let move_data = self.move_data(); let init_loc_map = &move_data.init_loc_map; @@ -652,7 +669,6 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { None } })); - terminator.edges() } fn apply_call_return_effect( diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index b690e86b747d5..da2ea948366db 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -1,8 +1,6 @@ use rustc_index::bit_set::DenseBitSet; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{ - self, CallReturnPlaces, Local, Location, Place, StatementKind, TerminatorEdges, -}; +use rustc_middle::mir::{self, CallReturnPlaces, Local, Location, Place, StatementKind}; use crate::{Analysis, Backward, GenKill}; @@ -55,14 +53,13 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals { TransferFunction(state).visit_statement(statement, location); } - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, + terminator: &mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { TransferFunction(state).visit_terminator(terminator, location); - terminator.edges() } fn apply_call_return_effect( @@ -301,14 +298,13 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { TransferFunction(state).visit_statement(statement, location); } - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - terminator: &'mir mir::Terminator<'tcx>, + terminator: &mir::Terminator<'tcx>, location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { TransferFunction(state).visit_terminator(terminator, location); - terminator.edges() } fn apply_call_return_effect( diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 494fb4098cfc1..558bf0a5603fa 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -295,12 +295,12 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage { } } - fn apply_primary_terminator_effect<'t>( + fn apply_primary_terminator_effect( &self, state: &mut Self::Domain, - terminator: &'t Terminator<'tcx>, + terminator: &Terminator<'tcx>, loc: Location, - ) -> TerminatorEdges<'t, 'tcx> { + ) { match terminator.kind { // For call terminators the destination requires storage for the call // and after the call returns successfully, but not after a panic. @@ -333,7 +333,6 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage { } self.check_for_move(state, loc); - terminator.edges() } fn apply_call_return_effect( diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 7f2e5c05eb5d3..4e00bf1bf6559 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -122,19 +122,34 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> { } } - fn apply_primary_terminator_effect<'mir>( + fn get_terminator_edges<'mir>( &self, - state: &mut Self::Domain, + state: &Self::Domain, terminator: &'mir Terminator<'tcx>, _location: Location, ) -> TerminatorEdges<'mir, 'tcx> { if state.is_reachable() { - self.handle_terminator(terminator, state) + if let TerminatorKind::SwitchInt { discr, targets } = &terminator.kind { + self.get_switch_int_edges(discr, targets, state) + } else { + terminator.edges() + } } else { TerminatorEdges::None } } + fn apply_primary_terminator_effect( + &self, + state: &mut Self::Domain, + terminator: &Terminator<'tcx>, + _location: Location, + ) { + if state.is_reachable() { + self.handle_terminator(terminator, state) + } + } + fn apply_call_return_effect( &self, state: &mut Self::Domain, @@ -204,16 +219,10 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } } - fn handle_operand( - &self, - operand: &Operand<'tcx>, - state: &mut State>, - ) -> ValueOrPlace> { + fn handle_operand(&self, operand: &Operand<'tcx>) -> ValueOrPlace> { match operand { Operand::RuntimeChecks(_) => ValueOrPlace::TOP, - Operand::Constant(constant) => { - ValueOrPlace::Value(self.handle_constant(constant, state)) - } + Operand::Constant(constant) => ValueOrPlace::Value(self.handle_constant(constant)), Operand::Copy(place) | Operand::Move(place) => { // On move, we would ideally flood the place with bottom. But with the current // framework this is not possible (similar to `InterpCx::eval_operand`). @@ -228,7 +237,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { &self, terminator: &'mir Terminator<'tcx>, state: &mut State>, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { match &terminator.kind { TerminatorKind::Call { .. } | TerminatorKind::InlineAsm { .. } => { // Effect is applied by `handle_call_return`. @@ -240,14 +249,12 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { // They would have an effect, but are not allowed in this phase. bug!("encountered disallowed terminator"); } - TerminatorKind::SwitchInt { discr, targets } => { - return self.handle_switch_int(discr, targets, state); - } TerminatorKind::TailCall { .. } => { // FIXME(explicit_tail_calls): determine if we need to do something here (probably // not) } - TerminatorKind::Goto { .. } + TerminatorKind::SwitchInt { .. } + | TerminatorKind::Goto { .. } | TerminatorKind::UnwindResume | TerminatorKind::UnwindTerminate(_) | TerminatorKind::Return @@ -259,7 +266,6 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { // These terminators have no effect on the analysis. } } - terminator.edges() } fn handle_call_return( @@ -376,7 +382,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { operand, _, ) => { - let pointer = self.handle_operand(operand, state); + let pointer = self.handle_operand(operand); state.assign(target.as_ref(), pointer, &self.map); if let Some(target_len) = self.map.find_len(target.as_ref()) @@ -461,7 +467,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } } Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), &self.map), - Rvalue::Use(operand, _) => return self.handle_operand(operand, state), + Rvalue::Use(operand, _) => return self.handle_operand(operand), Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"), Rvalue::Ref(..) | Rvalue::Reborrow(..) | Rvalue::RawPtr(..) => { // We don't track such places. @@ -480,24 +486,20 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { ValueOrPlace::Value(val) } - fn handle_constant( - &self, - constant: &ConstOperand<'tcx>, - _state: &mut State>, - ) -> FlatSet { + fn handle_constant(&self, constant: &ConstOperand<'tcx>) -> FlatSet { constant .const_ .try_eval_scalar(self.tcx, self.typing_env) .map_or(FlatSet::Top, FlatSet::Elem) } - fn handle_switch_int<'mir>( + fn get_switch_int_edges<'mir>( &self, discr: &'mir Operand<'tcx>, targets: &'mir SwitchTargets, - state: &mut State>, + state: &State>, ) -> TerminatorEdges<'mir, 'tcx> { - let value = match self.handle_operand(discr, state) { + let value = match self.handle_operand(discr) { ValueOrPlace::Value(value) => value, ValueOrPlace::Place(place) => state.get_idx(place, &self.map), }; @@ -676,7 +678,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { op: &Operand<'tcx>, state: &mut State>, ) -> FlatSet> { - let value = match self.handle_operand(op, state) { + let value = match self.handle_operand(op) { ValueOrPlace::Value(value) => value, ValueOrPlace::Place(place) => state.get_idx(place, &self.map), }; diff --git a/compiler/rustc_mir_transform/src/liveness.rs b/compiler/rustc_mir_transform/src/liveness.rs index 32951ea0162a6..c895819a9f8cc 100644 --- a/compiler/rustc_mir_transform/src/liveness.rs +++ b/compiler/rustc_mir_transform/src/liveness.rs @@ -1342,14 +1342,13 @@ impl<'tcx> Analysis<'tcx> for MaybeLivePlaces<'_, 'tcx> { self.transfer_function(trans).visit_statement(statement, location); } - fn apply_primary_terminator_effect<'mir>( + fn apply_primary_terminator_effect( &self, trans: &mut Self::Domain, - terminator: &'mir Terminator<'tcx>, + terminator: &Terminator<'tcx>, location: Location, - ) -> TerminatorEdges<'mir, 'tcx> { + ) { self.transfer_function(trans).visit_terminator(terminator, location); - terminator.edges() } fn apply_call_return_effect(