From 3ebe058fad91921a3b10e618d35f1d20e640834c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 27 Oct 2025 13:37:44 +1100 Subject: [PATCH 1/6] Make `ConstAnalysis::ecx` a `RefCell`. Of the many dataflow analyses, `ConstAnalysis` is the only one that requires the analysis be mutabile when used with `ResultsVisitor`. It's needed because of the `ecx` field -- `ecx.intern_with_temp_alloc` is called during visiting and it takes `&mut self`. This commit changes `ConstAnalysis` to use interior mutability for the `ecx` field. This is a bit annoying for `ConstAnalysis`, but it will allow more immutability in `ResultsVisitor`, as seen in the next commit. --- .../src/dataflow_const_prop.rs | 70 +++++++++++++------ 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 8bcda77f4bc32..a79b341ad1a7a 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -3,6 +3,7 @@ //! Currently, this pass only propagates scalar values. use std::assert_matches::assert_matches; +use std::cell::RefCell; use std::fmt::Formatter; use rustc_abi::{BackendRepr, FIRST_VARIANT, FieldIdx, Size, VariantIdx}; @@ -85,7 +86,7 @@ struct ConstAnalysis<'a, 'tcx> { map: Map<'tcx>, tcx: TyCtxt<'tcx>, local_decls: &'a LocalDecls<'tcx>, - ecx: InterpCx<'tcx, DummyMachine>, + ecx: RefCell>, typing_env: ty::TypingEnv<'tcx>, } @@ -153,7 +154,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { map, tcx, local_decls: &body.local_decls, - ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine), + ecx: RefCell::new(InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine)), typing_env, } } @@ -410,6 +411,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { match self.eval_operand(operand, state) { FlatSet::Elem(op) => self .ecx + .borrow() .int_to_int_or_float(&op, layout) .discard_err() .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)), @@ -424,6 +426,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { match self.eval_operand(operand, state) { FlatSet::Elem(op) => self .ecx + .borrow() .float_to_float_or_int(&op, layout) .discard_err() .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)), @@ -454,6 +457,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { match self.eval_operand(operand, state) { FlatSet::Elem(value) => self .ecx + .borrow() .unary_op(*op, &value) .discard_err() .map_or(FlatSet::Top, |val| self.wrap_immediate(*val)), @@ -468,6 +472,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { let val = match null_op { NullOp::OffsetOf(fields) => self .ecx + .borrow() .tcx .offset_of_subfield(self.typing_env, layout, fields.iter()) .bytes(), @@ -556,8 +561,11 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } } Operand::Constant(box constant) => { - if let Some(constant) = - self.ecx.eval_mir_constant(&constant.const_, constant.span, None).discard_err() + if let Some(constant) = self + .ecx + .borrow() + .eval_mir_constant(&constant.const_, constant.span, None) + .discard_err() { self.assign_constant(state, place, constant, &[]); } @@ -587,7 +595,9 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { return; } } - operand = if let Some(operand) = self.ecx.project(&operand, proj_elem).discard_err() { + operand = if let Some(operand) = + self.ecx.borrow().project(&operand, proj_elem).discard_err() + { operand } else { return; @@ -598,17 +608,22 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { place, operand, &mut |elem, op| match elem { - TrackElem::Field(idx) => self.ecx.project_field(op, idx).discard_err(), - TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_err(), + TrackElem::Field(idx) => self.ecx.borrow().project_field(op, idx).discard_err(), + TrackElem::Variant(idx) => { + self.ecx.borrow().project_downcast(op, idx).discard_err() + } TrackElem::Discriminant => { - let variant = self.ecx.read_discriminant(op).discard_err()?; - let discr_value = - self.ecx.discriminant_for_variant(op.layout.ty, variant).discard_err()?; + let variant = self.ecx.borrow().read_discriminant(op).discard_err()?; + let discr_value = self + .ecx + .borrow() + .discriminant_for_variant(op.layout.ty, variant) + .discard_err()?; Some(discr_value.into()) } TrackElem::DerefLen => { - let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_err()?.into(); - let len_usize = op.len(&self.ecx).discard_err()?; + let op: OpTy<'_> = self.ecx.borrow().deref_pointer(op).discard_err()?.into(); + let len_usize = op.len(&self.ecx.borrow()).discard_err()?; let layout = self .tcx .layout_of(self.typing_env.as_query_input(self.tcx.types.usize)) @@ -617,7 +632,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } }, &mut |place, op| { - if let Some(imm) = self.ecx.read_immediate_raw(op).discard_err() + if let Some(imm) = self.ecx.borrow().read_immediate_raw(op).discard_err() && let Some(imm) = imm.right() { let elem = self.wrap_immediate(*imm); @@ -641,7 +656,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { (FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom), // Both sides are known, do the actual computation. (FlatSet::Elem(left), FlatSet::Elem(right)) => { - match self.ecx.binary_op(op, &left, &right).discard_err() { + match self.ecx.borrow().binary_op(op, &left, &right).discard_err() { // Ideally this would return an Immediate, since it's sometimes // a pair and sometimes not. But as a hack we always return a pair // and just make the 2nd component `Bottom` when it does not exist. @@ -714,8 +729,11 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { return None; } let enum_ty_layout = self.tcx.layout_of(self.typing_env.as_query_input(enum_ty)).ok()?; - let discr_value = - self.ecx.discriminant_for_variant(enum_ty_layout.ty, variant_index).discard_err()?; + let discr_value = self + .ecx + .borrow() + .discriminant_for_variant(enum_ty_layout.ty, variant_index) + .discard_err()?; Some(discr_value.to_scalar()) } @@ -956,7 +974,7 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> OperandCollector { state, visitor: self, - ecx: &mut analysis.ecx, + ecx: &mut analysis.ecx.borrow_mut(), map: &analysis.map, } .visit_rvalue(rvalue, location); @@ -978,9 +996,12 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> // Don't overwrite the assignment if it already uses a constant (to keep the span). } StatementKind::Assign(box (place, _)) => { - if let Some(value) = - self.try_make_constant(&mut analysis.ecx, place, state, &analysis.map) - { + if let Some(value) = self.try_make_constant( + &mut analysis.ecx.borrow_mut(), + place, + state, + &analysis.map, + ) { self.patch.assignments.insert(location, value); } } @@ -995,8 +1016,13 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> terminator: &Terminator<'tcx>, location: Location, ) { - OperandCollector { state, visitor: self, ecx: &mut analysis.ecx, map: &analysis.map } - .visit_terminator(terminator, location); + OperandCollector { + state, + visitor: self, + ecx: &mut analysis.ecx.borrow_mut(), + map: &analysis.map, + } + .visit_terminator(terminator, location); } } From 958a2e4a3d57269f50f7973a4228c48c69419da3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 27 Oct 2025 15:11:10 +1100 Subject: [PATCH 2/6] Make `Analysis` immutable in `ResultsVisitor::visit_*` methods. This makes sense -- you wouldn't expect that visiting the results of an analysis would change the analysis itself. --- compiler/rustc_borrowck/src/lib.rs | 6 +++--- compiler/rustc_mir_dataflow/src/framework/graphviz.rs | 8 ++++---- compiler/rustc_mir_dataflow/src/framework/visitor.rs | 8 ++++---- compiler/rustc_mir_transform/src/coroutine.rs | 4 ++-- compiler/rustc_mir_transform/src/dataflow_const_prop.rs | 6 +++--- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index a57689a45b67b..3fef76b1fc406 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -790,7 +790,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> { fn visit_after_early_statement_effect( &mut self, - _analysis: &mut Borrowck<'a, 'tcx>, + _analysis: &Borrowck<'a, 'tcx>, state: &BorrowckDomain, stmt: &Statement<'tcx>, location: Location, @@ -865,7 +865,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, fn visit_after_early_terminator_effect( &mut self, - _analysis: &mut Borrowck<'a, 'tcx>, + _analysis: &Borrowck<'a, 'tcx>, state: &BorrowckDomain, term: &Terminator<'tcx>, loc: Location, @@ -985,7 +985,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, fn visit_after_primary_terminator_effect( &mut self, - _analysis: &mut Borrowck<'a, 'tcx>, + _analysis: &Borrowck<'a, 'tcx>, state: &BorrowckDomain, term: &Terminator<'tcx>, loc: Location, diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index b85b82b8f6d92..a55b7a8f67332 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -736,7 +736,7 @@ where fn visit_after_early_statement_effect( &mut self, - analysis: &mut A, + analysis: &A, state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, @@ -749,7 +749,7 @@ where fn visit_after_primary_statement_effect( &mut self, - analysis: &mut A, + analysis: &A, state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, @@ -760,7 +760,7 @@ where fn visit_after_early_terminator_effect( &mut self, - analysis: &mut A, + analysis: &A, state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, @@ -773,7 +773,7 @@ where fn visit_after_primary_terminator_effect( &mut self, - analysis: &mut A, + analysis: &A, state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index fbb9e4108726d..1bc9d2eff8eea 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -53,7 +53,7 @@ where /// Called after the "early" effect of the given statement is applied to `state`. fn visit_after_early_statement_effect( &mut self, - _analysis: &mut A, + _analysis: &A, _state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, @@ -63,7 +63,7 @@ where /// Called after the "primary" effect of the given statement is applied to `state`. fn visit_after_primary_statement_effect( &mut self, - _analysis: &mut A, + _analysis: &A, _state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, @@ -73,7 +73,7 @@ where /// Called after the "early" effect of the given terminator is applied to `state`. fn visit_after_early_terminator_effect( &mut self, - _analysis: &mut A, + _analysis: &A, _state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, @@ -85,7 +85,7 @@ where /// The `call_return_effect` (if one exists) will *not* be applied to `state`. fn visit_after_primary_terminator_effect( &mut self, - _analysis: &mut A, + _analysis: &A, _state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 2ccd8178e667b..fef93c5c5bdc6 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -942,7 +942,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, MaybeRequiresStorage<'a, 'tcx>> { fn visit_after_early_statement_effect( &mut self, - _analysis: &mut MaybeRequiresStorage<'a, 'tcx>, + _analysis: &MaybeRequiresStorage<'a, 'tcx>, state: &DenseBitSet, _statement: &Statement<'tcx>, loc: Location, @@ -952,7 +952,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, MaybeRequiresStorage<'a, 'tcx>> fn visit_after_early_terminator_effect( &mut self, - _analysis: &mut MaybeRequiresStorage<'a, 'tcx>, + _analysis: &MaybeRequiresStorage<'a, 'tcx>, state: &DenseBitSet, _terminator: &Terminator<'tcx>, loc: Location, diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index a79b341ad1a7a..433100ef95fb1 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -964,7 +964,7 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> #[instrument(level = "trace", skip(self, analysis, statement))] fn visit_after_early_statement_effect( &mut self, - analysis: &mut ConstAnalysis<'_, 'tcx>, + analysis: &ConstAnalysis<'_, 'tcx>, state: &State>, statement: &Statement<'tcx>, location: Location, @@ -986,7 +986,7 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> #[instrument(level = "trace", skip(self, analysis, statement))] fn visit_after_primary_statement_effect( &mut self, - analysis: &mut ConstAnalysis<'_, 'tcx>, + analysis: &ConstAnalysis<'_, 'tcx>, state: &State>, statement: &Statement<'tcx>, location: Location, @@ -1011,7 +1011,7 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> fn visit_after_early_terminator_effect( &mut self, - analysis: &mut ConstAnalysis<'_, 'tcx>, + analysis: &ConstAnalysis<'_, 'tcx>, state: &State>, terminator: &Terminator<'tcx>, location: Location, From 517b767fa1072ff915e1b4ae02557de48e11d7b6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 27 Oct 2025 16:50:21 +1100 Subject: [PATCH 3/6] Reorder args for `visit_results_in_block`. Put `analysis` first, to match `apply_effects_in_range`. --- compiler/rustc_mir_dataflow/src/framework/direction.rs | 6 +++--- compiler/rustc_mir_dataflow/src/framework/visitor.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 79c0db7d72831..1dd8fc40006dc 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -40,10 +40,10 @@ pub trait Direction { /// all locations in a basic block (starting from `entry_state` and to /// visit them with `vis`. fn visit_results_in_block<'mir, 'tcx, A>( + analysis: &mut A, state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - analysis: &mut A, vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>; @@ -206,10 +206,10 @@ impl Direction for Backward { } fn visit_results_in_block<'mir, 'tcx, A>( + analysis: &mut A, state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - analysis: &mut A, vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>, @@ -386,10 +386,10 @@ impl Direction for Forward { } fn visit_results_in_block<'mir, 'tcx, A>( + analysis: &mut A, state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - analysis: &mut A, vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>, diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index 1bc9d2eff8eea..9ec59dff0548a 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -24,7 +24,7 @@ pub fn visit_results<'mir, 'tcx, A>( let block_data = &body[block]; state.clone_from(&results[block]); - A::Direction::visit_results_in_block(&mut state, block, block_data, analysis, vis); + A::Direction::visit_results_in_block(analysis, &mut state, block, block_data, vis); } } From 8afbd9fe025d61848335fb268a6aad172ef41383 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 27 Oct 2025 16:04:02 +1100 Subject: [PATCH 4/6] Use a `RefCell` in `MaybeRequiresStorage`. This will let us make `Analysis` arguments in many other places immutable, in the next commit. --- .../rustc_mir_dataflow/src/impls/storage_liveness.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 026826fc379c7..a01db72ff7f73 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -1,4 +1,5 @@ use std::borrow::Cow; +use std::cell::RefCell; use rustc_index::bit_set::DenseBitSet; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; @@ -115,12 +116,12 @@ type BorrowedLocalsResults<'mir, 'tcx> = ResultsCursor<'mir, 'tcx, MaybeBorrowed /// Dataflow analysis that determines whether each local requires storage at a /// given location; i.e. whether its storage can go away without being observed. pub struct MaybeRequiresStorage<'mir, 'tcx> { - borrowed_locals: BorrowedLocalsResults<'mir, 'tcx>, + borrowed_locals: RefCell>, } impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { pub fn new(borrowed_locals: BorrowedLocalsResults<'mir, 'tcx>) -> Self { - MaybeRequiresStorage { borrowed_locals } + MaybeRequiresStorage { borrowed_locals: RefCell::new(borrowed_locals) } } } @@ -294,9 +295,10 @@ 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, state: &mut >::Domain, loc: Location) { - let body = self.borrowed_locals.body(); - let mut visitor = MoveVisitor { state, borrowed_locals: &mut self.borrowed_locals }; + fn check_for_move(&self, state: &mut >::Domain, loc: Location) { + let mut borrowed_locals = self.borrowed_locals.borrow_mut(); + let body = borrowed_locals.body(); + let mut visitor = MoveVisitor { state, borrowed_locals: &mut borrowed_locals }; visitor.visit_location(body, loc); } } From a97cd3ba57b1f07503ca3f121ea8b425decf8fcc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 27 Oct 2025 16:06:39 +1100 Subject: [PATCH 5/6] Make `Analysis` immutable in many more places. The `state: A::Domain` value is the primary things that's modified when performing an analysis. The `Analysis` impl is immutable in every case but one (`MaybeRequiredStorage`) and it now uses interior mutability. As well as changing many `&mut A` arguments to `&A`, this also: - lets `CowMut` be replaced with the simpler `SimpleCow` in `cursor.rs`; - removes the need for the `RefCell` in `Formatter`; - removes the need for `MaybeBorrowedLocals` to impl `Clone`, because it's a unit type and it's now clear that its constructor can be used directly instead of being put into a local variable and cloned. --- compiler/rustc_borrowck/src/dataflow.rs | 18 +++---- compiler/rustc_borrowck/src/lib.rs | 6 +-- .../src/check_consts/resolver.rs | 6 +-- .../src/framework/cursor.rs | 47 +++++++------------ .../src/framework/direction.rs | 18 +++---- .../src/framework/graphviz.rs | 22 ++++----- .../rustc_mir_dataflow/src/framework/mod.rs | 20 ++++---- .../rustc_mir_dataflow/src/framework/tests.rs | 8 ++-- .../src/framework/visitor.rs | 4 +- .../src/impls/borrowed_locals.rs | 5 +- .../src/impls/initialized.rs | 26 +++++----- .../rustc_mir_dataflow/src/impls/liveness.rs | 12 ++--- .../src/impls/storage_liveness.rs | 14 +++--- compiler/rustc_mir_transform/src/coroutine.rs | 29 ++++-------- .../src/dataflow_const_prop.rs | 10 ++-- compiler/rustc_mir_transform/src/liveness.rs | 6 +-- 16 files changed, 111 insertions(+), 140 deletions(-) diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 84d5ffb947914..813ceaeb8da9f 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -44,7 +44,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { } fn apply_early_statement_effect( - &mut self, + &self, state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, @@ -55,7 +55,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, loc: Location, @@ -66,7 +66,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { } fn apply_early_terminator_effect( - &mut self, + &self, state: &mut Self::Domain, term: &mir::Terminator<'tcx>, loc: Location, @@ -77,7 +77,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, term: &'mir mir::Terminator<'tcx>, loc: Location, @@ -92,7 +92,7 @@ impl<'a, 'tcx> Analysis<'tcx> for Borrowck<'a, 'tcx> { } fn apply_call_return_effect( - &mut self, + &self, _state: &mut Self::Domain, _block: BasicBlock, _return_places: CallReturnPlaces<'_, 'tcx>, @@ -533,7 +533,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { } fn apply_early_statement_effect( - &mut self, + &self, state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, @@ -542,7 +542,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, location: Location, @@ -590,7 +590,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { } fn apply_early_terminator_effect( - &mut self, + &self, state: &mut Self::Domain, _terminator: &mir::Terminator<'tcx>, location: Location, @@ -599,7 +599,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, _location: Location, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 3fef76b1fc406..a33241ebe70ac 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -537,13 +537,13 @@ fn borrowck_check_region_constraints<'tcx>( mbcx.report_region_errors(nll_errors); } - let (mut flow_analysis, flow_entry_states) = + let (flow_analysis, flow_results) = get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx); visit_results( body, traversal::reverse_postorder(body).map(|(bb, _)| bb), - &mut flow_analysis, - &flow_entry_states, + &flow_analysis, + &flow_results, &mut mbcx, ); diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index 664dda8701a63..e6e3948305af7 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -332,7 +332,7 @@ where } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, @@ -341,7 +341,7 @@ where } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, @@ -351,7 +351,7 @@ where } fn apply_call_return_effect( - &mut self, + &self, state: &mut Self::Domain, block: BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index 3f6e7a0661921..8799caa3e28f5 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -1,8 +1,7 @@ //! Random access inspection of the results of a dataflow analysis. -use std::borrow::Cow; use std::cmp::Ordering; -use std::ops::{Deref, DerefMut}; +use std::ops::Deref; #[cfg(debug_assertions)] use rustc_index::bit_set::DenseBitSet; @@ -10,30 +9,20 @@ use rustc_middle::mir::{self, BasicBlock, Location}; use super::{Analysis, Direction, Effect, EffectIndex, Results}; -/// Some `ResultsCursor`s want to own an `Analysis`, and some want to borrow an `Analysis`, either -/// mutable or immutably. This type allows all of the above. It's similar to `Cow`, but `Cow` -/// doesn't allow mutable borrowing. -enum CowMut<'a, T> { - BorrowedMut(&'a mut T), +/// This is like `Cow`, but it lacks the `T: ToOwned` bound and doesn't support +/// `to_owned`/`into_owned`. +enum SimpleCow<'a, T> { + Borrowed(&'a T), Owned(T), } -impl Deref for CowMut<'_, T> { +impl Deref for SimpleCow<'_, T> { type Target = T; fn deref(&self) -> &T { match self { - CowMut::BorrowedMut(borrowed) => borrowed, - CowMut::Owned(owned) => owned, - } - } -} - -impl DerefMut for CowMut<'_, T> { - fn deref_mut(&mut self) -> &mut T { - match self { - CowMut::BorrowedMut(borrowed) => borrowed, - CowMut::Owned(owned) => owned, + SimpleCow::Borrowed(borrowed) => borrowed, + SimpleCow::Owned(owned) => owned, } } } @@ -53,8 +42,8 @@ where A: Analysis<'tcx>, { body: &'mir mir::Body<'tcx>, - analysis: CowMut<'mir, A>, - results: Cow<'mir, Results>, + analysis: SimpleCow<'mir, A>, + results: SimpleCow<'mir, Results>, state: A::Domain, pos: CursorPosition, @@ -84,8 +73,8 @@ where fn new( body: &'mir mir::Body<'tcx>, - analysis: CowMut<'mir, A>, - results: Cow<'mir, Results>, + analysis: SimpleCow<'mir, A>, + results: SimpleCow<'mir, Results>, ) -> Self { let bottom_value = analysis.bottom_value(body); ResultsCursor { @@ -111,16 +100,16 @@ where analysis: A, results: Results, ) -> Self { - Self::new(body, CowMut::Owned(analysis), Cow::Owned(results)) + Self::new(body, SimpleCow::Owned(analysis), SimpleCow::Owned(results)) } /// Returns a new cursor that borrows and inspects analysis results. pub fn new_borrowing( body: &'mir mir::Body<'tcx>, - analysis: &'mir mut A, + analysis: &'mir A, results: &'mir Results, ) -> Self { - Self::new(body, CowMut::BorrowedMut(analysis), Cow::Borrowed(results)) + Self::new(body, SimpleCow::Borrowed(analysis), SimpleCow::Borrowed(results)) } /// Allows inspection of unreachable basic blocks even with `debug_assertions` enabled. @@ -236,7 +225,7 @@ where let target_effect_index = effect.at_index(target.statement_index); A::Direction::apply_effects_in_range( - &mut *self.analysis, + &*self.analysis, &mut self.state, target.block, block_data, @@ -251,8 +240,8 @@ where /// /// This can be used, e.g., to apply the call return effect directly to the cursor without /// creating an extra copy of the dataflow state. - pub fn apply_custom_effect(&mut self, f: impl FnOnce(&mut A, &mut A::Domain)) { - f(&mut self.analysis, &mut self.state); + pub fn apply_custom_effect(&mut self, f: impl FnOnce(&A, &mut A::Domain)) { + f(&self.analysis, &mut self.state); self.state_needs_reset = true; } } diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index 1dd8fc40006dc..b15b5c07ce382 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -14,7 +14,7 @@ pub trait Direction { /// Called by `iterate_to_fixpoint` during initial analysis computation. fn apply_effects_in_block<'mir, 'tcx, A>( - analysis: &mut A, + analysis: &A, body: &mir::Body<'tcx>, state: &mut A::Domain, block: BasicBlock, @@ -28,7 +28,7 @@ pub trait Direction { /// /// `effects.start()` must precede or equal `effects.end()` in this direction. fn apply_effects_in_range<'tcx, A>( - analysis: &mut A, + analysis: &A, state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, @@ -40,7 +40,7 @@ pub trait Direction { /// all locations in a basic block (starting from `entry_state` and to /// visit them with `vis`. fn visit_results_in_block<'mir, 'tcx, A>( - analysis: &mut A, + analysis: &A, state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, @@ -56,7 +56,7 @@ impl Direction for Backward { const IS_FORWARD: bool = false; fn apply_effects_in_block<'mir, 'tcx, A>( - analysis: &mut A, + analysis: &A, body: &mir::Body<'tcx>, state: &mut A::Domain, block: BasicBlock, @@ -129,7 +129,7 @@ impl Direction for Backward { } fn apply_effects_in_range<'tcx, A>( - analysis: &mut A, + analysis: &A, state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, @@ -206,7 +206,7 @@ impl Direction for Backward { } fn visit_results_in_block<'mir, 'tcx, A>( - analysis: &mut A, + analysis: &A, state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, @@ -242,7 +242,7 @@ impl Direction for Forward { const IS_FORWARD: bool = true; fn apply_effects_in_block<'mir, 'tcx, A>( - analysis: &mut A, + analysis: &A, body: &mir::Body<'tcx>, state: &mut A::Domain, block: BasicBlock, @@ -312,7 +312,7 @@ impl Direction for Forward { } fn apply_effects_in_range<'tcx, A>( - analysis: &mut A, + analysis: &A, state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, @@ -386,7 +386,7 @@ impl Direction for Forward { } fn visit_results_in_block<'mir, 'tcx, A>( - analysis: &mut A, + analysis: &A, state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index a55b7a8f67332..f9d9106ba7af3 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -1,7 +1,6 @@ //! A helpful diagram for debugging dataflow problems. use std::borrow::Cow; -use std::cell::RefCell; use std::ffi::OsString; use std::path::PathBuf; use std::sync::OnceLock; @@ -33,7 +32,7 @@ use crate::errors::{ pub(super) fn write_graphviz_results<'tcx, A>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - analysis: &mut A, + analysis: &A, results: &Results, pass_name: Option<&'static str>, ) -> std::io::Result<()> @@ -206,11 +205,7 @@ where A: Analysis<'tcx>, { body: &'mir Body<'tcx>, - // The `RefCell` is used because `::node_label` - // takes `&self`, but it needs to modify the analysis. This is also the - // reason for the `Formatter`/`BlockFormatter` split; `BlockFormatter` has - // the operations that involve the mutation, i.e. within the `borrow_mut`. - analysis: RefCell<&'mir mut A>, + analysis: &'mir A, results: &'mir Results, style: OutputStyle, reachable: DenseBitSet, @@ -222,12 +217,12 @@ where { fn new( body: &'mir Body<'tcx>, - analysis: &'mir mut A, + analysis: &'mir A, results: &'mir Results, style: OutputStyle, ) -> Self { let reachable = traversal::reachable_as_bitset(body); - Formatter { body, analysis: analysis.into(), results, style, reachable } + Formatter { body, analysis, results, style, reachable } } } @@ -265,12 +260,11 @@ where } fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { - let analysis = &mut **self.analysis.borrow_mut(); - - let diffs = StateDiffCollector::run(self.body, *block, analysis, self.results, self.style); + let diffs = + StateDiffCollector::run(self.body, *block, self.analysis, self.results, self.style); let mut fmt = BlockFormatter { - cursor: ResultsCursor::new_borrowing(self.body, analysis, self.results), + cursor: ResultsCursor::new_borrowing(self.body, self.analysis, self.results), style: self.style, bg: Background::Light, }; @@ -698,7 +692,7 @@ impl StateDiffCollector { fn run<'tcx, A>( body: &Body<'tcx>, block: BasicBlock, - analysis: &mut A, + analysis: &A, results: &Results, style: OutputStyle, ) -> Self diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index b6a5603601959..9e1fc5a59fe34 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -136,7 +136,7 @@ pub trait Analysis<'tcx> { /// analyses should not implement this without also implementing /// `apply_primary_statement_effect`. fn apply_early_statement_effect( - &mut self, + &self, _state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, _location: Location, @@ -145,7 +145,7 @@ pub trait Analysis<'tcx> { /// Updates the current dataflow state with the effect of evaluating a statement. fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, @@ -159,7 +159,7 @@ pub trait Analysis<'tcx> { /// analyses should not implement this without also implementing /// `apply_primary_terminator_effect`. fn apply_early_terminator_effect( - &mut self, + &self, _state: &mut Self::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, @@ -173,7 +173,7 @@ pub trait Analysis<'tcx> { /// `InitializedPlaces` analyses, the return place for a function call is not marked as /// initialized here. fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, _state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, _location: Location, @@ -189,7 +189,7 @@ pub trait Analysis<'tcx> { /// This is separate from `apply_primary_terminator_effect` to properly track state across /// unwind edges. fn apply_call_return_effect( - &mut self, + &self, _state: &mut Self::Domain, _block: BasicBlock, _return_places: CallReturnPlaces<'_, 'tcx>, @@ -211,7 +211,7 @@ pub trait Analysis<'tcx> { /// engine doesn't need to clone the exit state for a block unless /// `get_switch_int_data` is actually called. fn get_switch_int_data( - &mut self, + &self, _block: mir::BasicBlock, _discr: &mir::Operand<'tcx>, ) -> Option { @@ -220,7 +220,7 @@ pub trait Analysis<'tcx> { /// See comments on `get_switch_int_data`. fn apply_switch_int_edge_effect( - &mut self, + &self, _data: &mut Self::SwitchIntData, _state: &mut Self::Domain, _value: SwitchTargetValue, @@ -245,7 +245,7 @@ pub trait Analysis<'tcx> { /// Without a `pass_name` to differentiates them, only the results for the latest run will be /// saved. fn iterate_to_fixpoint<'mir>( - mut self, + self, tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, pass_name: Option<&'static str>, @@ -285,7 +285,7 @@ pub trait Analysis<'tcx> { state.clone_from(&results[bb]); Self::Direction::apply_effects_in_block( - &mut self, + &self, body, &mut state, bb, @@ -300,7 +300,7 @@ pub trait Analysis<'tcx> { } if tcx.sess.opts.unstable_opts.dump_mir_dataflow { - let res = write_graphviz_results(tcx, body, &mut self, &results, pass_name); + let res = write_graphviz_results(tcx, body, &self, &results, pass_name); if let Err(e) = res { error!("Failed to write graphviz dataflow results: {}", e); } diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 23e28a11a452b..36d0f3a947bc6 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -175,7 +175,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> { } fn apply_early_statement_effect( - &mut self, + &self, state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, @@ -185,7 +185,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, @@ -195,7 +195,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> { } fn apply_early_terminator_effect( - &mut self, + &self, state: &mut Self::Domain, _terminator: &mir::Terminator<'tcx>, location: Location, @@ -205,7 +205,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index 9ec59dff0548a..28ae08d1e6b19 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -7,7 +7,7 @@ use super::{Analysis, Direction, Results}; pub fn visit_results<'mir, 'tcx, A>( body: &'mir mir::Body<'tcx>, blocks: impl IntoIterator, - analysis: &mut A, + analysis: &A, results: &Results, vis: &mut impl ResultsVisitor<'tcx, A>, ) where @@ -31,7 +31,7 @@ pub fn visit_results<'mir, 'tcx, A>( /// Like `visit_results`, but only for reachable blocks. pub fn visit_reachable_results<'mir, 'tcx, A>( body: &'mir mir::Body<'tcx>, - analysis: &mut A, + analysis: &A, results: &Results, vis: &mut impl ResultsVisitor<'tcx, A>, ) where diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index a4e4e30a8bb6c..331e41bd126b7 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -11,7 +11,6 @@ use crate::{Analysis, GenKill}; /// At present, this is used as a very limited form of alias analysis. For example, /// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for /// immovable coroutines. -#[derive(Clone)] pub struct MaybeBorrowedLocals; impl MaybeBorrowedLocals { @@ -34,7 +33,7 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, statement: &Statement<'tcx>, location: Location, @@ -43,7 +42,7 @@ impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir Terminator<'tcx>, location: Location, diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 5937d68f389e4..9216106b6eddc 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -376,7 +376,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, @@ -400,7 +400,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, @@ -429,7 +429,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } fn apply_call_return_effect( - &mut self, + &self, state: &mut Self::Domain, _block: mir::BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, @@ -448,7 +448,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } fn get_switch_int_data( - &mut self, + &self, block: mir::BasicBlock, discr: &mir::Operand<'tcx>, ) -> Option { @@ -460,7 +460,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { } fn apply_switch_int_edge_effect( - &mut self, + &self, data: &mut Self::SwitchIntData, state: &mut Self::Domain, value: SwitchTargetValue, @@ -513,7 +513,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, @@ -527,7 +527,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, @@ -545,7 +545,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } fn apply_call_return_effect( - &mut self, + &self, state: &mut Self::Domain, _block: mir::BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, @@ -564,7 +564,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } fn get_switch_int_data( - &mut self, + &self, block: mir::BasicBlock, discr: &mir::Operand<'tcx>, ) -> Option { @@ -580,7 +580,7 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { } fn apply_switch_int_edge_effect( - &mut self, + &self, data: &mut Self::SwitchIntData, state: &mut Self::Domain, value: SwitchTargetValue, @@ -627,7 +627,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { #[instrument(skip(self, state), level = "debug")] fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, stmt: &mir::Statement<'tcx>, location: Location, @@ -652,7 +652,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { #[instrument(skip(self, state, terminator), level = "debug")] fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, @@ -674,7 +674,7 @@ impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { } fn apply_call_return_effect( - &mut self, + &self, state: &mut Self::Domain, block: mir::BasicBlock, _return_places: CallReturnPlaces<'_, 'tcx>, diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 596da18e3d1b4..e439f2e052fe8 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -41,7 +41,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, @@ -50,7 +50,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, @@ -60,7 +60,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals { } fn apply_call_return_effect( - &mut self, + &self, state: &mut Self::Domain, _block: mir::BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, @@ -278,7 +278,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, @@ -294,7 +294,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir mir::Terminator<'tcx>, location: Location, @@ -304,7 +304,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { } fn apply_call_return_effect( - &mut self, + &self, state: &mut Self::Domain, _block: mir::BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index a01db72ff7f73..3702f7c55a431 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -54,7 +54,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageLive<'a> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, stmt: &Statement<'tcx>, _: Location, @@ -98,7 +98,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeStorageDead<'a> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, stmt: &Statement<'tcx>, _: Location, @@ -144,7 +144,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { } fn apply_early_statement_effect( - &mut self, + &self, state: &mut Self::Domain, stmt: &Statement<'tcx>, loc: Location, @@ -177,7 +177,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, _: &Statement<'tcx>, loc: Location, @@ -188,7 +188,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { } fn apply_early_terminator_effect( - &mut self, + &self, state: &mut Self::Domain, terminator: &Terminator<'tcx>, loc: Location, @@ -243,7 +243,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { } fn apply_primary_terminator_effect<'t>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'t Terminator<'tcx>, loc: Location, @@ -284,7 +284,7 @@ impl<'tcx> Analysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { } fn apply_call_return_effect( - &mut self, + &self, state: &mut Self::Domain, _block: BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index fef93c5c5bdc6..1fc109533ca23 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -720,27 +720,16 @@ fn locals_live_across_suspend_points<'tcx>( // Calculate the MIR locals that have been previously borrowed (even if they are still active). let borrowed_locals = MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")); - let mut borrowed_locals_analysis1 = borrowed_locals.analysis; - let mut borrowed_locals_analysis2 = borrowed_locals_analysis1.clone(); // trivial - let borrowed_locals_cursor1 = ResultsCursor::new_borrowing( - body, - &mut borrowed_locals_analysis1, - &borrowed_locals.results, - ); - let mut borrowed_locals_cursor2 = ResultsCursor::new_borrowing( - body, - &mut borrowed_locals_analysis2, - &borrowed_locals.results, - ); + let borrowed_locals_cursor1 = + ResultsCursor::new_borrowing(body, &MaybeBorrowedLocals, &borrowed_locals.results); + let mut borrowed_locals_cursor2 = + ResultsCursor::new_borrowing(body, &MaybeBorrowedLocals, &borrowed_locals.results); // Calculate the MIR locals that we need to keep storage around for. - let mut requires_storage = + let requires_storage = MaybeRequiresStorage::new(borrowed_locals_cursor1).iterate_to_fixpoint(tcx, body, None); - let mut requires_storage_cursor = ResultsCursor::new_borrowing( - body, - &mut requires_storage.analysis, - &requires_storage.results, - ); + let mut requires_storage_cursor = + ResultsCursor::new_borrowing(body, &requires_storage.analysis, &requires_storage.results); // Calculate the liveness of MIR locals ignoring borrows. let mut liveness = @@ -812,7 +801,7 @@ fn locals_live_across_suspend_points<'tcx>( body, &saved_locals, always_live_locals.clone(), - &mut requires_storage.analysis, + &requires_storage.analysis, &requires_storage.results, ); @@ -878,7 +867,7 @@ fn compute_storage_conflicts<'mir, 'tcx>( body: &'mir Body<'tcx>, saved_locals: &'mir CoroutineSavedLocals, always_live_locals: DenseBitSet, - analysis: &mut MaybeRequiresStorage<'mir, 'tcx>, + analysis: &MaybeRequiresStorage<'mir, 'tcx>, results: &Results>, ) -> BitMatrix { assert_eq!(body.local_decls.len(), saved_locals.domain_size()); diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 433100ef95fb1..f849a788c361f 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -61,13 +61,13 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp { let map = Map::new(tcx, body, place_limit); // Perform the actual dataflow analysis. - let mut const_ = debug_span!("analyze") + let const_ = debug_span!("analyze") .in_scope(|| ConstAnalysis::new(tcx, body, map).iterate_to_fixpoint(tcx, body, None)); // Collect results and patch the body afterwards. let mut visitor = Collector::new(tcx, &body.local_decls); debug_span!("collect").in_scope(|| { - visit_reachable_results(body, &mut const_.analysis, &const_.results, &mut visitor) + visit_reachable_results(body, &const_.analysis, &const_.results, &mut visitor) }); let mut patch = visitor.patch; debug_span!("patch").in_scope(|| patch.visit_body_preserves_cfg(body)); @@ -112,7 +112,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> { } fn apply_primary_statement_effect( - &mut self, + &self, state: &mut Self::Domain, statement: &Statement<'tcx>, _location: Location, @@ -123,7 +123,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, state: &mut Self::Domain, terminator: &'mir Terminator<'tcx>, _location: Location, @@ -136,7 +136,7 @@ impl<'tcx> Analysis<'tcx> for ConstAnalysis<'_, 'tcx> { } fn apply_call_return_effect( - &mut self, + &self, state: &mut Self::Domain, _block: BasicBlock, return_places: CallReturnPlaces<'_, 'tcx>, diff --git a/compiler/rustc_mir_transform/src/liveness.rs b/compiler/rustc_mir_transform/src/liveness.rs index 82f9dfe4745d2..840bb169a1fa3 100644 --- a/compiler/rustc_mir_transform/src/liveness.rs +++ b/compiler/rustc_mir_transform/src/liveness.rs @@ -1160,7 +1160,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLivePlaces<'_, 'tcx> { } fn apply_primary_statement_effect( - &mut self, + &self, trans: &mut Self::Domain, statement: &Statement<'tcx>, location: Location, @@ -1169,7 +1169,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLivePlaces<'_, 'tcx> { } fn apply_primary_terminator_effect<'mir>( - &mut self, + &self, trans: &mut Self::Domain, terminator: &'mir Terminator<'tcx>, location: Location, @@ -1179,7 +1179,7 @@ impl<'tcx> Analysis<'tcx> for MaybeLivePlaces<'_, 'tcx> { } fn apply_call_return_effect( - &mut self, + &self, _trans: &mut Self::Domain, _block: BasicBlock, _return_places: CallReturnPlaces<'_, 'tcx>, From 87932397024a9053ca028adbba8315fc93cfa343 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 28 Oct 2025 09:41:58 +1100 Subject: [PATCH 6/6] Put `Analysis` back into `Results`. `Results` used to contain an `Analysis`, but it was removed in #140234. That change made sense because the analysis was mutable but the entry states were immutable and it was good to separate them so the mutability of the different pieces was clear. Now that analyses are immutable there is no need for the separation, lots of analysis+results pairs can be combined, and the names are going back to what they were before: - `Results` -> `EntryStates` - `AnalysisAndResults` -> `Results` --- compiler/rustc_borrowck/src/lib.rs | 18 +++++----- .../src/framework/cursor.rs | 36 ++++++------------- .../src/framework/graphviz.rs | 29 ++++++--------- .../rustc_mir_dataflow/src/framework/mod.rs | 25 +++++++------ .../src/framework/results.rs | 18 +++++----- .../rustc_mir_dataflow/src/framework/tests.rs | 10 +++--- .../src/framework/visitor.rs | 14 ++++---- compiler/rustc_mir_dataflow/src/lib.rs | 5 +-- compiler/rustc_mir_transform/src/coroutine.rs | 17 ++++----- .../src/dataflow_const_prop.rs | 4 +-- compiler/rustc_mir_transform/src/dest_prop.rs | 8 ++--- 11 files changed, 77 insertions(+), 107 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index a33241ebe70ac..d4d38301a1586 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -49,7 +49,7 @@ use rustc_mir_dataflow::move_paths::{ InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex, }; use rustc_mir_dataflow::points::DenseLocationMap; -use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor, visit_results}; +use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results}; use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT}; use rustc_span::{ErrorGuaranteed, Span, Symbol}; use smallvec::SmallVec; @@ -537,12 +537,10 @@ fn borrowck_check_region_constraints<'tcx>( mbcx.report_region_errors(nll_errors); } - let (flow_analysis, flow_results) = - get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx); + let flow_results = get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx); visit_results( body, traversal::reverse_postorder(body).map(|(bb, _)| bb), - &flow_analysis, &flow_results, &mut mbcx, ); @@ -604,7 +602,7 @@ fn get_flow_results<'a, 'tcx>( move_data: &'a MoveData<'tcx>, borrow_set: &'a BorrowSet<'tcx>, regioncx: &RegionInferenceContext<'tcx>, -) -> (Borrowck<'a, 'tcx>, Results) { +) -> Results<'tcx, Borrowck<'a, 'tcx>> { // We compute these three analyses individually, but them combine them into // a single results so that `mbcx` can visit them all together. let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint( @@ -629,14 +627,14 @@ fn get_flow_results<'a, 'tcx>( ever_inits: ever_inits.analysis, }; - assert_eq!(borrows.results.len(), uninits.results.len()); - assert_eq!(borrows.results.len(), ever_inits.results.len()); - let results: Results<_> = - itertools::izip!(borrows.results, uninits.results, ever_inits.results) + assert_eq!(borrows.entry_states.len(), uninits.entry_states.len()); + assert_eq!(borrows.entry_states.len(), ever_inits.entry_states.len()); + let entry_states: EntryStates<_> = + itertools::izip!(borrows.entry_states, uninits.entry_states, ever_inits.entry_states) .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits }) .collect(); - (analysis, results) + Results { analysis, entry_states } } pub(crate) struct BorrowckInferCtxt<'tcx> { diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index 8799caa3e28f5..3c56999fcbdc9 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -42,8 +42,7 @@ where A: Analysis<'tcx>, { body: &'mir mir::Body<'tcx>, - analysis: SimpleCow<'mir, A>, - results: SimpleCow<'mir, Results>, + results: SimpleCow<'mir, Results<'tcx, A>>, state: A::Domain, pos: CursorPosition, @@ -71,15 +70,10 @@ where self.body } - fn new( - body: &'mir mir::Body<'tcx>, - analysis: SimpleCow<'mir, A>, - results: SimpleCow<'mir, Results>, - ) -> Self { - let bottom_value = analysis.bottom_value(body); + fn new(body: &'mir mir::Body<'tcx>, results: SimpleCow<'mir, Results<'tcx, A>>) -> Self { + let bottom_value = results.analysis.bottom_value(body); ResultsCursor { body, - analysis, results, // Initialize to the `bottom_value` and set `state_needs_reset` to tell the cursor that @@ -95,21 +89,13 @@ where } /// Returns a new cursor that takes ownership of and inspects analysis results. - pub fn new_owning( - body: &'mir mir::Body<'tcx>, - analysis: A, - results: Results, - ) -> Self { - Self::new(body, SimpleCow::Owned(analysis), SimpleCow::Owned(results)) + pub fn new_owning(body: &'mir mir::Body<'tcx>, results: Results<'tcx, A>) -> Self { + Self::new(body, SimpleCow::Owned(results)) } /// Returns a new cursor that borrows and inspects analysis results. - pub fn new_borrowing( - body: &'mir mir::Body<'tcx>, - analysis: &'mir A, - results: &'mir Results, - ) -> Self { - Self::new(body, SimpleCow::Borrowed(analysis), SimpleCow::Borrowed(results)) + pub fn new_borrowing(body: &'mir mir::Body<'tcx>, results: &'mir Results<'tcx, A>) -> Self { + Self::new(body, SimpleCow::Borrowed(results)) } /// Allows inspection of unreachable basic blocks even with `debug_assertions` enabled. @@ -121,7 +107,7 @@ where /// Returns the `Analysis` used to generate the underlying `Results`. pub fn analysis(&self) -> &A { - &self.analysis + &self.results.analysis } /// Resets the cursor to hold the entry set for the given basic block. @@ -133,7 +119,7 @@ where #[cfg(debug_assertions)] assert!(self.reachable_blocks.contains(block)); - self.state.clone_from(&self.results[block]); + self.state.clone_from(&self.results.entry_states[block]); self.pos = CursorPosition::block_entry(block); self.state_needs_reset = false; } @@ -225,7 +211,7 @@ where let target_effect_index = effect.at_index(target.statement_index); A::Direction::apply_effects_in_range( - &*self.analysis, + &self.results.analysis, &mut self.state, target.block, block_data, @@ -241,7 +227,7 @@ where /// This can be used, e.g., to apply the call return effect directly to the cursor without /// creating an extra copy of the dataflow state. pub fn apply_custom_effect(&mut self, f: impl FnOnce(&A, &mut A::Domain)) { - f(&self.analysis, &mut self.state); + f(&self.results.analysis, &mut self.state); self.state_needs_reset = true; } } diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index f9d9106ba7af3..22bff3806b156 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -32,8 +32,7 @@ use crate::errors::{ pub(super) fn write_graphviz_results<'tcx, A>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - analysis: &A, - results: &Results, + results: &Results<'tcx, A>, pass_name: Option<&'static str>, ) -> std::io::Result<()> where @@ -80,7 +79,7 @@ where let mut buf = Vec::new(); - let graphviz = Formatter::new(body, analysis, results, style); + let graphviz = Formatter::new(body, results, style); let mut render_opts = vec![dot::RenderOption::Fontname(tcx.sess.opts.unstable_opts.graphviz_font.clone())]; if tcx.sess.opts.unstable_opts.graphviz_dark_mode { @@ -205,8 +204,7 @@ where A: Analysis<'tcx>, { body: &'mir Body<'tcx>, - analysis: &'mir A, - results: &'mir Results, + results: &'mir Results<'tcx, A>, style: OutputStyle, reachable: DenseBitSet, } @@ -215,14 +213,9 @@ impl<'mir, 'tcx, A> Formatter<'mir, 'tcx, A> where A: Analysis<'tcx>, { - fn new( - body: &'mir Body<'tcx>, - analysis: &'mir A, - results: &'mir Results, - style: OutputStyle, - ) -> Self { + fn new(body: &'mir Body<'tcx>, results: &'mir Results<'tcx, A>, style: OutputStyle) -> Self { let reachable = traversal::reachable_as_bitset(body); - Formatter { body, analysis, results, style, reachable } + Formatter { body, results, style, reachable } } } @@ -260,11 +253,10 @@ where } fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { - let diffs = - StateDiffCollector::run(self.body, *block, self.analysis, self.results, self.style); + let diffs = StateDiffCollector::run(self.body, *block, self.results, self.style); let mut fmt = BlockFormatter { - cursor: ResultsCursor::new_borrowing(self.body, self.analysis, self.results), + cursor: ResultsCursor::new_borrowing(self.body, self.results), style: self.style, bg: Background::Light, }; @@ -692,8 +684,7 @@ impl StateDiffCollector { fn run<'tcx, A>( body: &Body<'tcx>, block: BasicBlock, - analysis: &A, - results: &Results, + results: &Results<'tcx, A>, style: OutputStyle, ) -> Self where @@ -701,12 +692,12 @@ impl StateDiffCollector { D: DebugWithContext, { let mut collector = StateDiffCollector { - prev_state: analysis.bottom_value(body), + prev_state: results.analysis.bottom_value(body), after: vec![], before: (style == OutputStyle::BeforeAndAfter).then_some(vec![]), }; - visit_results(body, std::iter::once(block), analysis, results, &mut collector); + visit_results(body, std::iter::once(block), results, &mut collector); collector } } diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 9e1fc5a59fe34..60b3c15d80d79 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -58,8 +58,7 @@ mod visitor; pub use self::cursor::ResultsCursor; pub use self::direction::{Backward, Direction, Forward}; pub use self::lattice::{JoinSemiLattice, MaybeReachable}; -pub(crate) use self::results::AnalysisAndResults; -pub use self::results::Results; +pub use self::results::{EntryStates, Results}; pub use self::visitor::{ResultsVisitor, visit_reachable_results, visit_results}; /// Analysis domains are all bitsets of various kinds. This trait holds @@ -249,15 +248,17 @@ pub trait Analysis<'tcx> { tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, pass_name: Option<&'static str>, - ) -> AnalysisAndResults<'tcx, Self> + ) -> Results<'tcx, Self> where Self: Sized, Self::Domain: DebugWithContext, { - let mut results = IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len()); - self.initialize_start_block(body, &mut results[mir::START_BLOCK]); + let mut entry_states = + IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len()); + self.initialize_start_block(body, &mut entry_states[mir::START_BLOCK]); - if Self::Direction::IS_BACKWARD && results[mir::START_BLOCK] != self.bottom_value(body) { + if Self::Direction::IS_BACKWARD && entry_states[mir::START_BLOCK] != self.bottom_value(body) + { bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); } @@ -281,8 +282,8 @@ pub trait Analysis<'tcx> { let mut state = self.bottom_value(body); while let Some(bb) = dirty_queue.pop() { // Set the state to the entry state of the block. This is equivalent to `state = - // results[bb].clone()`, but it saves an allocation, thus improving compile times. - state.clone_from(&results[bb]); + // entry_states[bb].clone()`, but it saves an allocation, thus improving compile times. + state.clone_from(&entry_states[bb]); Self::Direction::apply_effects_in_block( &self, @@ -291,7 +292,7 @@ pub trait Analysis<'tcx> { bb, &body[bb], |target: BasicBlock, state: &Self::Domain| { - let set_changed = results[target].join(state); + let set_changed = entry_states[target].join(state); if set_changed { dirty_queue.insert(target); } @@ -299,14 +300,16 @@ pub trait Analysis<'tcx> { ); } + let results = Results { analysis: self, entry_states }; + if tcx.sess.opts.unstable_opts.dump_mir_dataflow { - let res = write_graphviz_results(tcx, body, &self, &results, pass_name); + let res = write_graphviz_results(tcx, body, &results, pass_name); if let Err(e) = res { error!("Failed to write graphviz dataflow results: {}", e); } } - AnalysisAndResults { analysis: self, results } + results } } diff --git a/compiler/rustc_mir_dataflow/src/framework/results.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs index 7b7e981d3a554..76b6cc47dde4a 100644 --- a/compiler/rustc_mir_dataflow/src/framework/results.rs +++ b/compiler/rustc_mir_dataflow/src/framework/results.rs @@ -5,26 +5,26 @@ use rustc_middle::mir::{BasicBlock, Body}; use super::{Analysis, ResultsCursor}; -/// The results of a dataflow analysis that has converged to fixpoint. It only holds the domain -/// values at the entry of each basic block. Domain values in other parts of the block are -/// recomputed on the fly by visitors (i.e. `ResultsCursor`, or `ResultsVisitor` impls). -pub type Results = IndexVec; +pub type EntryStates = IndexVec; -/// Utility type used in a few places where it's convenient to bundle an analysis with its results. -pub struct AnalysisAndResults<'tcx, A> +/// The results of a dataflow analysis that has converged to fixpoint. It holds the domain values +/// (states) at the entry of each basic block. Domain values in other parts of the block are +/// recomputed on the fly by visitors (i.e. `ResultsCursor`, or `ResultsVisitor` impls). The +/// analysis is also present because it's often needed alongside the entry states. +pub struct Results<'tcx, A> where A: Analysis<'tcx>, { pub analysis: A, - pub results: Results, + pub entry_states: EntryStates, } -impl<'tcx, A> AnalysisAndResults<'tcx, A> +impl<'tcx, A> Results<'tcx, A> where A: Analysis<'tcx>, { /// Creates a `ResultsCursor` that takes ownership of `self`. pub fn into_results_cursor<'mir>(self, body: &'mir Body<'tcx>) -> ResultsCursor<'mir, 'tcx, A> { - ResultsCursor::new_owning(body, self.analysis, self.results) + ResultsCursor::new_owning(body, self) } } diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 36d0f3a947bc6..85f23b8332a1c 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -71,15 +71,15 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> { /// /// | Location | Before | After | /// |------------------------|-------------------|--------| -/// | (on_entry) | {102} || +/// | (on_entry) | {102} | | /// | statement 0 | +0 | +1 | /// | statement 1 | +2 | +3 | /// | `Call` terminator | +4 | +5 | -/// | (on unwind) | {102,0,1,2,3,4,5} || +/// | (on unwind) | {102,0,1,2,3,4,5} | | /// /// The `102` in the block's entry set is derived from the basic block index and ensures that the /// expected state is unique across all basic blocks. Remember, it is generated by -/// `mock_results`, not from actually running `MockAnalysis` to fixpoint. +/// `mock_entry_states`, not from actually running `MockAnalysis` to fixpoint. struct MockAnalysis<'tcx, D> { body: &'tcx mir::Body<'tcx>, dir: PhantomData, @@ -96,7 +96,7 @@ impl MockAnalysis<'_, D> { ret } - fn mock_results(&self) -> IndexVec> { + fn mock_entry_states(&self) -> IndexVec> { let empty = self.bottom_value(self.body); let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks); @@ -255,7 +255,7 @@ fn test_cursor(analysis: MockAnalysis<'_, D>) { let body = analysis.body; let mut cursor = - AnalysisAndResults { results: analysis.mock_results(), analysis }.into_results_cursor(body); + Results { entry_states: analysis.mock_entry_states(), analysis }.into_results_cursor(body); cursor.allow_unreachable(); diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index 28ae08d1e6b19..46940c6ab62fc 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -7,13 +7,12 @@ use super::{Analysis, Direction, Results}; pub fn visit_results<'mir, 'tcx, A>( body: &'mir mir::Body<'tcx>, blocks: impl IntoIterator, - analysis: &A, - results: &Results, + results: &Results<'tcx, A>, vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>, { - let mut state = analysis.bottom_value(body); + let mut state = results.analysis.bottom_value(body); #[cfg(debug_assertions)] let reachable_blocks = mir::traversal::reachable_as_bitset(body); @@ -23,22 +22,21 @@ pub fn visit_results<'mir, 'tcx, A>( assert!(reachable_blocks.contains(block)); let block_data = &body[block]; - state.clone_from(&results[block]); - A::Direction::visit_results_in_block(analysis, &mut state, block, block_data, vis); + state.clone_from(&results.entry_states[block]); + A::Direction::visit_results_in_block(&results.analysis, &mut state, block, block_data, vis); } } /// Like `visit_results`, but only for reachable blocks. pub fn visit_reachable_results<'mir, 'tcx, A>( body: &'mir mir::Body<'tcx>, - analysis: &A, - results: &Results, + results: &Results<'tcx, A>, vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>, { let blocks = traversal::reachable(body).map(|(bb, _)| bb); - visit_results(body, blocks, analysis, results, vis) + visit_results(body, blocks, results, vis) } /// A visitor over the results of an `Analysis`. Use this when you want to inspect domain values in diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 2e8c916544160..485925e7b50cd 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -17,8 +17,9 @@ pub use self::drop_flag_effects::{ move_path_children_matching, on_all_children_bits, on_lookup_result_bits, }; pub use self::framework::{ - Analysis, Backward, Direction, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results, - ResultsCursor, ResultsVisitor, fmt, graphviz, lattice, visit_reachable_results, visit_results, + Analysis, Backward, Direction, EntryStates, Forward, GenKill, JoinSemiLattice, MaybeReachable, + Results, ResultsCursor, ResultsVisitor, fmt, graphviz, lattice, visit_reachable_results, + visit_results, }; use self::move_paths::MoveData; diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 1fc109533ca23..069fcfefac21e 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -720,16 +720,13 @@ fn locals_live_across_suspend_points<'tcx>( // Calculate the MIR locals that have been previously borrowed (even if they are still active). let borrowed_locals = MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")); - let borrowed_locals_cursor1 = - ResultsCursor::new_borrowing(body, &MaybeBorrowedLocals, &borrowed_locals.results); - let mut borrowed_locals_cursor2 = - ResultsCursor::new_borrowing(body, &MaybeBorrowedLocals, &borrowed_locals.results); + let borrowed_locals_cursor1 = ResultsCursor::new_borrowing(body, &borrowed_locals); + let mut borrowed_locals_cursor2 = ResultsCursor::new_borrowing(body, &borrowed_locals); // Calculate the MIR locals that we need to keep storage around for. let requires_storage = MaybeRequiresStorage::new(borrowed_locals_cursor1).iterate_to_fixpoint(tcx, body, None); - let mut requires_storage_cursor = - ResultsCursor::new_borrowing(body, &requires_storage.analysis, &requires_storage.results); + let mut requires_storage_cursor = ResultsCursor::new_borrowing(body, &requires_storage); // Calculate the liveness of MIR locals ignoring borrows. let mut liveness = @@ -801,8 +798,7 @@ fn locals_live_across_suspend_points<'tcx>( body, &saved_locals, always_live_locals.clone(), - &requires_storage.analysis, - &requires_storage.results, + &requires_storage, ); LivenessInfo { @@ -867,8 +863,7 @@ fn compute_storage_conflicts<'mir, 'tcx>( body: &'mir Body<'tcx>, saved_locals: &'mir CoroutineSavedLocals, always_live_locals: DenseBitSet, - analysis: &MaybeRequiresStorage<'mir, 'tcx>, - results: &Results>, + results: &Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>, ) -> BitMatrix { assert_eq!(body.local_decls.len(), saved_locals.domain_size()); @@ -888,7 +883,7 @@ fn compute_storage_conflicts<'mir, 'tcx>( eligible_storage_live: DenseBitSet::new_empty(body.local_decls.len()), }; - visit_reachable_results(body, analysis, results, &mut visitor); + visit_reachable_results(body, results, &mut visitor); let local_conflicts = visitor.local_conflicts; diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index f849a788c361f..8532e1e9d7cc9 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -66,9 +66,7 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp { // Collect results and patch the body afterwards. let mut visitor = Collector::new(tcx, &body.local_decls); - debug_span!("collect").in_scope(|| { - visit_reachable_results(body, &const_.analysis, &const_.results, &mut visitor) - }); + debug_span!("collect").in_scope(|| visit_reachable_results(body, &const_, &mut visitor)); let mut patch = visitor.patch; debug_span!("patch").in_scope(|| patch.visit_body_preserves_cfg(body)); } diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index a10e0b82467cc..8c2149ef96fb0 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -146,7 +146,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use rustc_mir_dataflow::impls::{DefUse, MaybeLiveLocals}; use rustc_mir_dataflow::points::DenseLocationMap; -use rustc_mir_dataflow::{Analysis, Results}; +use rustc_mir_dataflow::{Analysis, EntryStates}; use tracing::{debug, trace}; pub(super) struct DestinationPropagation; @@ -173,7 +173,7 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation { let points = DenseLocationMap::new(body); let mut relevant = RelevantLocals::compute(&candidates, body.local_decls.len()); - let mut live = save_as_intervals(&points, body, &relevant, live.results); + let mut live = save_as_intervals(&points, body, &relevant, live.entry_states); dest_prop_mir_dump(tcx, body, &points, &live, &relevant); @@ -506,7 +506,7 @@ fn save_as_intervals<'tcx>( elements: &DenseLocationMap, body: &Body<'tcx>, relevant: &RelevantLocals, - results: Results>, + entry_states: EntryStates>, ) -> SparseIntervalMatrix { let mut values = SparseIntervalMatrix::new(2 * elements.num_points()); let mut state = MaybeLiveLocals.bottom_value(body); @@ -529,7 +529,7 @@ fn save_as_intervals<'tcx>( continue; } - state.clone_from(&results[block]); + state.clone_from(&entry_states[block]); let block_data = &body.basic_blocks[block]; let loc = Location { block, statement_index: block_data.statements.len() };