about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs18
-rw-r--r--compiler/rustc_borrowck/src/lib.rs9
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/resolver.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/cursor.rs112
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs60
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/engine.rs102
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs98
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs61
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/tests.rs13
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/visitor.rs45
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs7
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs18
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/mod.rs28
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs87
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs5
-rw-r--r--compiler/rustc_mir_dataflow/src/rustc_peek.rs23
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs8
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs60
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs19
19 files changed, 491 insertions, 288 deletions
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 167f245361a..9e0a9a3b6f4 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -59,7 +59,7 @@ macro_rules! impl_visitable {
             }
 
             fn reconstruct_before_statement_effect(
-                &self,
+                &mut self,
                 state: &mut Self::FlowState,
                 stmt: &mir::Statement<'tcx>,
                 loc: Location,
@@ -69,7 +69,7 @@ macro_rules! impl_visitable {
             }
 
             fn reconstruct_statement_effect(
-                &self,
+                &mut self,
                 state: &mut Self::FlowState,
                 stmt: &mir::Statement<'tcx>,
                 loc: Location,
@@ -79,7 +79,7 @@ macro_rules! impl_visitable {
             }
 
             fn reconstruct_before_terminator_effect(
-                &self,
+                &mut self,
                 state: &mut Self::FlowState,
                 term: &mir::Terminator<'tcx>,
                 loc: Location,
@@ -89,7 +89,7 @@ macro_rules! impl_visitable {
             }
 
             fn reconstruct_terminator_effect(
-                &self,
+                &mut self,
                 state: &mut Self::FlowState,
                 term: &mir::Terminator<'tcx>,
                 loc: Location,
@@ -341,7 +341,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
     type Idx = BorrowIndex;
 
     fn before_statement_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         _statement: &mir::Statement<'tcx>,
         location: Location,
@@ -350,7 +350,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
     }
 
     fn statement_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         stmt: &mir::Statement<'tcx>,
         location: Location,
@@ -398,7 +398,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
     }
 
     fn before_terminator_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         _terminator: &mir::Terminator<'tcx>,
         location: Location,
@@ -407,7 +407,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
     }
 
     fn terminator_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         terminator: &mir::Terminator<'tcx>,
         _location: Location,
@@ -424,7 +424,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
     }
 
     fn call_return_effect(
-        &self,
+        &mut self,
         _trans: &mut impl GenKill<Self::Idx>,
         _block: mir::BasicBlock,
         _return_places: CallReturnPlaces<'_, 'tcx>,
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index eb25d454339..c00efdaa9ac 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -372,7 +372,7 @@ fn do_mir_borrowck<'tcx>(
     // Compute and report region errors, if any.
     mbcx.report_region_errors(nll_errors);
 
-    let results = BorrowckResults {
+    let mut results = BorrowckResults {
         ever_inits: flow_ever_inits,
         uninits: flow_uninits,
         borrows: flow_borrows,
@@ -383,7 +383,7 @@ fn do_mir_borrowck<'tcx>(
     rustc_mir_dataflow::visit_results(
         body,
         traversal::reverse_postorder(body).map(|(bb, _)| bb),
-        &results,
+        &mut results,
         &mut mbcx,
     );
 
@@ -618,11 +618,12 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
 // 2. loans made in overlapping scopes do not conflict
 // 3. assignments do not affect things loaned out as immutable
 // 4. moves do not affect things loaned out in any way
-impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx> {
+impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorrowckCtxt<'cx, 'tcx> {
     type FlowState = Flows<'cx, 'tcx>;
 
     fn visit_statement_before_primary_effect(
         &mut self,
+        _results: &R,
         flow_state: &Flows<'cx, 'tcx>,
         stmt: &'cx Statement<'tcx>,
         location: Location,
@@ -692,6 +693,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
 
     fn visit_terminator_before_primary_effect(
         &mut self,
+        _results: &R,
         flow_state: &Flows<'cx, 'tcx>,
         term: &'cx Terminator<'tcx>,
         loc: Location,
@@ -800,6 +802,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
 
     fn visit_terminator_after_primary_effect(
         &mut self,
+        _results: &R,
         flow_state: &Flows<'cx, 'tcx>,
         term: &'cx Terminator<'tcx>,
         loc: Location,
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index 78c74e1892d..65fe164f8ec 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -337,7 +337,7 @@ where
     Q: Qualif,
 {
     fn apply_statement_effect(
-        &self,
+        &mut self,
         state: &mut Self::Domain,
         statement: &mir::Statement<'tcx>,
         location: Location,
@@ -346,7 +346,7 @@ where
     }
 
     fn apply_terminator_effect(
-        &self,
+        &mut self,
         state: &mut Self::Domain,
         terminator: &mir::Terminator<'tcx>,
         location: Location,
@@ -355,7 +355,7 @@ where
     }
 
     fn apply_call_return_effect(
-        &self,
+        &mut 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 f3b5544aa8b..c978bddfef5 100644
--- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
@@ -1,18 +1,60 @@
 //! Random access inspection of the results of a dataflow analysis.
 
-use crate::framework::BitSetExt;
+use crate::{framework::BitSetExt, CloneAnalysis};
 
-use std::borrow::Borrow;
+use std::borrow::{Borrow, BorrowMut};
 use std::cmp::Ordering;
 
 #[cfg(debug_assertions)]
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::{self, BasicBlock, Location};
 
-use super::{Analysis, Direction, Effect, EffectIndex, Results};
+use super::{Analysis, Direction, Effect, EffectIndex, EntrySets, Results, ResultsCloned};
+
+// `AnalysisResults` is needed as an impl such as the following has an unconstrained type
+// parameter:
+// ```
+// impl<'tcx, A, E, R> ResultsCursor<'_, 'tcx, A, R>
+// where
+//     A: Analysis<'tcx>,
+//     E: Borrow<EntrySets<'tcx, A>>,
+//     R: Results<'tcx, A, E>,
+// {}
+// ```
+
+/// A type representing the analysis results consumed by a `ResultsCursor`.
+pub trait AnalysisResults<'tcx, A>: BorrowMut<Results<'tcx, A, Self::EntrySets>>
+where
+    A: Analysis<'tcx>,
+{
+    /// The type containing the entry sets for this `Results` type.
+    ///
+    /// Should be either `EntrySets<'tcx, A>` or `&EntrySets<'tcx, A>`.
+    type EntrySets: Borrow<EntrySets<'tcx, A>>;
+}
+impl<'tcx, A, E> AnalysisResults<'tcx, A> for Results<'tcx, A, E>
+where
+    A: Analysis<'tcx>,
+    E: Borrow<EntrySets<'tcx, A>>,
+{
+    type EntrySets = E;
+}
+impl<'a, 'tcx, A, E> AnalysisResults<'tcx, A> for &'a mut Results<'tcx, A, E>
+where
+    A: Analysis<'tcx>,
+    E: Borrow<EntrySets<'tcx, A>>,
+{
+    type EntrySets = E;
+}
 
 /// A `ResultsCursor` that borrows the underlying `Results`.
-pub type ResultsRefCursor<'a, 'mir, 'tcx, A> = ResultsCursor<'mir, 'tcx, A, &'a Results<'tcx, A>>;
+pub type ResultsRefCursor<'res, 'mir, 'tcx, A> =
+    ResultsCursor<'mir, 'tcx, A, &'res mut Results<'tcx, A>>;
+
+/// A `ResultsCursor` which uses a cloned `Analysis` while borrowing the underlying `Results`. This
+/// allows multiple cursors over the same `Results`.
+pub type ResultsClonedCursor<'res, 'mir, 'tcx, A> =
+    ResultsCursor<'mir, 'tcx, A, ResultsCloned<'res, 'tcx, A>>;
 
 /// Allows random access inspection of the results of a dataflow analysis.
 ///
@@ -45,7 +87,38 @@ where
 impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
 where
     A: Analysis<'tcx>,
-    R: Borrow<Results<'tcx, A>>,
+{
+    /// Returns the dataflow state at the current location.
+    pub fn get(&self) -> &A::Domain {
+        &self.state
+    }
+
+    /// Returns the body this analysis was run on.
+    pub fn body(&self) -> &'mir mir::Body<'tcx> {
+        self.body
+    }
+
+    /// Unwraps this cursor, returning the underlying `Results`.
+    pub fn into_results(self) -> R {
+        self.results
+    }
+}
+
+impl<'res, 'mir, 'tcx, A> ResultsCursor<'mir, 'tcx, A, ResultsCloned<'res, 'tcx, A>>
+where
+    A: Analysis<'tcx> + CloneAnalysis,
+{
+    /// Creates a new cursor over the same `Results`. Note that the cursor's position is *not*
+    /// copied.
+    pub fn new_cursor(&self) -> Self {
+        Self::new(self.body, self.results.reclone_analysis())
+    }
+}
+
+impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
+where
+    A: Analysis<'tcx>,
+    R: AnalysisResults<'tcx, A>,
 {
     /// Returns a new cursor that can inspect `results`.
     pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self {
@@ -74,8 +147,13 @@ where
     }
 
     /// Returns the underlying `Results`.
-    pub fn results(&self) -> &Results<'tcx, A> {
-        &self.results.borrow()
+    pub fn results(&mut self) -> &Results<'tcx, A, R::EntrySets> {
+        self.results.borrow()
+    }
+
+    /// Returns the underlying `Results`.
+    pub fn mut_results(&mut self) -> &mut Results<'tcx, A, R::EntrySets> {
+        self.results.borrow_mut()
     }
 
     /// Returns the `Analysis` used to generate the underlying `Results`.
@@ -83,9 +161,14 @@ where
         &self.results.borrow().analysis
     }
 
-    /// Returns the dataflow state at the current location.
-    pub fn get(&self) -> &A::Domain {
-        &self.state
+    /// Returns the `Analysis` used to generate the underlying `Results`.
+    pub fn mut_analysis(&mut self) -> &mut A {
+        &mut self.results.borrow_mut().analysis
+    }
+
+    /// Returns both the dataflow state at the current location and the `Analysis`.
+    pub fn get_with_analysis(&mut self) -> (&A::Domain, &mut A) {
+        (&self.state, &mut self.results.borrow_mut().analysis)
     }
 
     /// Resets the cursor to hold the entry set for the given basic block.
@@ -97,7 +180,7 @@ where
         #[cfg(debug_assertions)]
         assert!(self.reachable_blocks.contains(block));
 
-        self.state.clone_from(&self.results.borrow().entry_set_for_block(block));
+        self.state.clone_from(self.results.borrow().entry_set_for_block(block));
         self.pos = CursorPosition::block_entry(block);
         self.state_needs_reset = false;
     }
@@ -186,7 +269,7 @@ where
             )
         };
 
-        let analysis = &self.results.borrow().analysis;
+        let analysis = &mut self.results.borrow_mut().analysis;
         let target_effect_index = effect.at_index(target.statement_index);
 
         A::Direction::apply_effects_in_range(
@@ -205,8 +288,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(&A, &mut A::Domain)) {
-        f(&self.results.borrow().analysis, &mut self.state);
+    pub fn apply_custom_effect(&mut self, f: impl FnOnce(&mut A, &mut A::Domain)) {
+        f(&mut self.results.borrow_mut().analysis, &mut self.state);
         self.state_needs_reset = true;
     }
 }
@@ -215,7 +298,6 @@ impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
 where
     A: crate::GenKillAnalysis<'tcx>,
     A::Domain: BitSetExt<A::Idx>,
-    R: Borrow<Results<'tcx, A>>,
 {
     pub fn contains(&self, elem: A::Idx) -> bool {
         self.get().contains(elem)
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index c8fe1af6674..f6100a90a04 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -16,7 +16,7 @@ pub trait Direction {
     ///
     /// `effects.start()` must precede or equal `effects.end()` in this direction.
     fn apply_effects_in_range<'tcx, A>(
-        analysis: &A,
+        analysis: &mut A,
         state: &mut A::Domain,
         block: BasicBlock,
         block_data: &mir::BasicBlockData<'tcx>,
@@ -25,7 +25,7 @@ pub trait Direction {
         A: Analysis<'tcx>;
 
     fn apply_effects_in_block<'tcx, A>(
-        analysis: &A,
+        analysis: &mut A,
         state: &mut A::Domain,
         block: BasicBlock,
         block_data: &mir::BasicBlockData<'tcx>,
@@ -33,7 +33,7 @@ pub trait Direction {
         A: Analysis<'tcx>;
 
     fn gen_kill_effects_in_block<'tcx, A>(
-        analysis: &A,
+        analysis: &mut A,
         trans: &mut GenKillSet<A::Idx>,
         block: BasicBlock,
         block_data: &mir::BasicBlockData<'tcx>,
@@ -44,13 +44,13 @@ pub trait Direction {
         state: &mut F,
         block: BasicBlock,
         block_data: &'mir mir::BasicBlockData<'tcx>,
-        results: &R,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>,
+        results: &mut R,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>,
     ) where
         R: ResultsVisitable<'tcx, FlowState = F>;
 
     fn join_state_into_successors_of<'tcx, A>(
-        analysis: &A,
+        analysis: &mut A,
         tcx: TyCtxt<'tcx>,
         body: &mir::Body<'tcx>,
         exit_state: &mut A::Domain,
@@ -67,7 +67,7 @@ impl Direction for Backward {
     const IS_FORWARD: bool = false;
 
     fn apply_effects_in_block<'tcx, A>(
-        analysis: &A,
+        analysis: &mut A,
         state: &mut A::Domain,
         block: BasicBlock,
         block_data: &mir::BasicBlockData<'tcx>,
@@ -87,7 +87,7 @@ impl Direction for Backward {
     }
 
     fn gen_kill_effects_in_block<'tcx, A>(
-        analysis: &A,
+        analysis: &mut A,
         trans: &mut GenKillSet<A::Idx>,
         block: BasicBlock,
         block_data: &mir::BasicBlockData<'tcx>,
@@ -107,7 +107,7 @@ impl Direction for Backward {
     }
 
     fn apply_effects_in_range<'tcx, A>(
-        analysis: &A,
+        analysis: &mut A,
         state: &mut A::Domain,
         block: BasicBlock,
         block_data: &mir::BasicBlockData<'tcx>,
@@ -187,36 +187,36 @@ impl Direction for Backward {
         state: &mut F,
         block: BasicBlock,
         block_data: &'mir mir::BasicBlockData<'tcx>,
-        results: &R,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>,
+        results: &mut R,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>,
     ) where
         R: ResultsVisitable<'tcx, FlowState = F>,
     {
         results.reset_to_block_entry(state, block);
 
-        vis.visit_block_end(&state, block_data, block);
+        vis.visit_block_end(results, &state, block_data, block);
 
         // Terminator
         let loc = Location { block, statement_index: block_data.statements.len() };
         let term = block_data.terminator();
         results.reconstruct_before_terminator_effect(state, term, loc);
-        vis.visit_terminator_before_primary_effect(state, term, loc);
+        vis.visit_terminator_before_primary_effect(results, state, term, loc);
         results.reconstruct_terminator_effect(state, term, loc);
-        vis.visit_terminator_after_primary_effect(state, term, loc);
+        vis.visit_terminator_after_primary_effect(results, state, term, loc);
 
         for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() {
             let loc = Location { block, statement_index };
             results.reconstruct_before_statement_effect(state, stmt, loc);
-            vis.visit_statement_before_primary_effect(state, stmt, loc);
+            vis.visit_statement_before_primary_effect(results, state, stmt, loc);
             results.reconstruct_statement_effect(state, stmt, loc);
-            vis.visit_statement_after_primary_effect(state, stmt, loc);
+            vis.visit_statement_after_primary_effect(results, state, stmt, loc);
         }
 
-        vis.visit_block_start(state, block_data, block);
+        vis.visit_block_start(results, state, block_data, block);
     }
 
     fn join_state_into_successors_of<'tcx, A>(
-        analysis: &A,
+        analysis: &mut A,
         _tcx: TyCtxt<'tcx>,
         body: &mir::Body<'tcx>,
         exit_state: &mut A::Domain,
@@ -319,7 +319,7 @@ impl Direction for Forward {
     const IS_FORWARD: bool = true;
 
     fn apply_effects_in_block<'tcx, A>(
-        analysis: &A,
+        analysis: &mut A,
         state: &mut A::Domain,
         block: BasicBlock,
         block_data: &mir::BasicBlockData<'tcx>,
@@ -339,7 +339,7 @@ impl Direction for Forward {
     }
 
     fn gen_kill_effects_in_block<'tcx, A>(
-        analysis: &A,
+        analysis: &mut A,
         trans: &mut GenKillSet<A::Idx>,
         block: BasicBlock,
         block_data: &mir::BasicBlockData<'tcx>,
@@ -359,7 +359,7 @@ impl Direction for Forward {
     }
 
     fn apply_effects_in_range<'tcx, A>(
-        analysis: &A,
+        analysis: &mut A,
         state: &mut A::Domain,
         block: BasicBlock,
         block_data: &mir::BasicBlockData<'tcx>,
@@ -435,35 +435,35 @@ impl Direction for Forward {
         state: &mut F,
         block: BasicBlock,
         block_data: &'mir mir::BasicBlockData<'tcx>,
-        results: &R,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>,
+        results: &mut R,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>,
     ) where
         R: ResultsVisitable<'tcx, FlowState = F>,
     {
         results.reset_to_block_entry(state, block);
 
-        vis.visit_block_start(state, block_data, block);
+        vis.visit_block_start(results, state, block_data, block);
 
         for (statement_index, stmt) in block_data.statements.iter().enumerate() {
             let loc = Location { block, statement_index };
             results.reconstruct_before_statement_effect(state, stmt, loc);
-            vis.visit_statement_before_primary_effect(state, stmt, loc);
+            vis.visit_statement_before_primary_effect(results, state, stmt, loc);
             results.reconstruct_statement_effect(state, stmt, loc);
-            vis.visit_statement_after_primary_effect(state, stmt, loc);
+            vis.visit_statement_after_primary_effect(results, state, stmt, loc);
         }
 
         let loc = Location { block, statement_index: block_data.statements.len() };
         let term = block_data.terminator();
         results.reconstruct_before_terminator_effect(state, term, loc);
-        vis.visit_terminator_before_primary_effect(state, term, loc);
+        vis.visit_terminator_before_primary_effect(results, state, term, loc);
         results.reconstruct_terminator_effect(state, term, loc);
-        vis.visit_terminator_after_primary_effect(state, term, loc);
+        vis.visit_terminator_after_primary_effect(results, state, term, loc);
 
-        vis.visit_block_end(state, block_data, block);
+        vis.visit_block_end(results, state, block_data, block);
     }
 
     fn join_state_into_successors_of<'tcx, A>(
-        analysis: &A,
+        analysis: &mut A,
         _tcx: TyCtxt<'tcx>,
         _body: &mir::Body<'tcx>,
         exit_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 3e8f792e634..4bdfa35fc70 100644
--- a/compiler/rustc_mir_dataflow/src/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs
@@ -5,7 +5,9 @@ use crate::errors::{
 };
 use crate::framework::BitSetExt;
 
+use std::borrow::Borrow;
 use std::ffi::OsString;
+use std::marker::PhantomData;
 use std::path::PathBuf;
 
 use rustc_ast as ast;
@@ -22,54 +24,108 @@ use rustc_span::symbol::{sym, Symbol};
 use super::fmt::DebugWithContext;
 use super::graphviz;
 use super::{
-    visit_results, Analysis, Direction, GenKill, GenKillAnalysis, GenKillSet, JoinSemiLattice,
-    ResultsCursor, ResultsVisitor,
+    visit_results, Analysis, AnalysisDomain, CloneAnalysis, Direction, GenKill, GenKillAnalysis,
+    GenKillSet, JoinSemiLattice, ResultsClonedCursor, ResultsCursor, ResultsRefCursor,
+    ResultsVisitor,
 };
 
+pub type EntrySets<'tcx, A> = IndexVec<BasicBlock, <A as AnalysisDomain<'tcx>>::Domain>;
+
 /// A dataflow analysis that has converged to fixpoint.
-pub struct Results<'tcx, A>
+pub struct Results<'tcx, A, E = EntrySets<'tcx, A>>
 where
     A: Analysis<'tcx>,
 {
     pub analysis: A,
-    pub(super) entry_sets: IndexVec<BasicBlock, A::Domain>,
+    pub(super) entry_sets: E,
+    pub(super) _marker: PhantomData<&'tcx ()>,
 }
 
-impl<'tcx, A> Results<'tcx, A>
+/// `Results` type with a cloned `Analysis` and borrowed entry sets.
+pub type ResultsCloned<'res, 'tcx, A> = Results<'tcx, A, &'res EntrySets<'tcx, A>>;
+
+impl<'tcx, A, E> Results<'tcx, A, E>
 where
     A: Analysis<'tcx>,
+    E: Borrow<EntrySets<'tcx, A>>,
 {
     /// Creates a `ResultsCursor` that can inspect these `Results`.
     pub fn into_results_cursor<'mir>(
         self,
         body: &'mir mir::Body<'tcx>,
-    ) -> ResultsCursor<'mir, 'tcx, A> {
+    ) -> ResultsCursor<'mir, 'tcx, A, Self> {
         ResultsCursor::new(body, self)
     }
 
     /// Gets the dataflow state for the given block.
     pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain {
-        &self.entry_sets[block]
+        &self.entry_sets.borrow()[block]
     }
 
     pub fn visit_with<'mir>(
-        &self,
+        &mut self,
         body: &'mir mir::Body<'tcx>,
         blocks: impl IntoIterator<Item = BasicBlock>,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>,
     ) {
         visit_results(body, blocks, self, vis)
     }
 
     pub fn visit_reachable_with<'mir>(
-        &self,
+        &mut self,
         body: &'mir mir::Body<'tcx>,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>,
+        vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, FlowState = A::Domain>,
     ) {
         let blocks = mir::traversal::reachable(body);
         visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
     }
 }
+impl<'tcx, A> Results<'tcx, A>
+where
+    A: Analysis<'tcx>,
+{
+    /// Creates a `ResultsCursor` that can inspect these `Results`.
+    pub fn as_results_cursor<'a, 'mir>(
+        &'a mut self,
+        body: &'mir mir::Body<'tcx>,
+    ) -> ResultsRefCursor<'a, 'mir, 'tcx, A> {
+        ResultsCursor::new(body, self)
+    }
+}
+impl<'tcx, A> Results<'tcx, A>
+where
+    A: Analysis<'tcx> + CloneAnalysis,
+{
+    /// Creates a new `Results` type with a cloned `Analysis` and borrowed entry sets.
+    pub fn clone_analysis(&self) -> ResultsCloned<'_, 'tcx, A> {
+        Results {
+            analysis: self.analysis.clone_analysis(),
+            entry_sets: &self.entry_sets,
+            _marker: PhantomData,
+        }
+    }
+
+    /// Creates a `ResultsCursor` that can inspect these `Results`.
+    pub fn cloned_results_cursor<'mir>(
+        &self,
+        body: &'mir mir::Body<'tcx>,
+    ) -> ResultsClonedCursor<'_, 'mir, 'tcx, A> {
+        self.clone_analysis().into_results_cursor(body)
+    }
+}
+impl<'res, 'tcx, A> Results<'tcx, A, &'res EntrySets<'tcx, A>>
+where
+    A: Analysis<'tcx> + CloneAnalysis,
+{
+    /// Creates a new `Results` type with a cloned `Analysis` and borrowed entry sets.
+    pub fn reclone_analysis(&self) -> Self {
+        Results {
+            analysis: self.analysis.clone_analysis(),
+            entry_sets: self.entry_sets,
+            _marker: PhantomData,
+        }
+    }
+}
 
 /// A solver for dataflow problems.
 pub struct Engine<'a, 'tcx, A>
@@ -98,7 +154,7 @@ where
     T: Idx,
 {
     /// Creates a new `Engine` to solve a gen-kill dataflow problem.
-    pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, analysis: A) -> Self {
+    pub fn new_gen_kill(tcx: TyCtxt<'tcx>, body: &'a 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).
         //
@@ -114,7 +170,7 @@ where
 
         for (block, block_data) in body.basic_blocks.iter_enumerated() {
             let trans = &mut trans_for_block[block];
-            A::Direction::gen_kill_effects_in_block(&analysis, trans, block, block_data);
+            A::Direction::gen_kill_effects_in_block(&mut analysis, trans, block, block_data);
         }
 
         let apply_trans = Box::new(move |bb: BasicBlock, state: &mut A::Domain| {
@@ -171,7 +227,13 @@ where
         A::Domain: DebugWithContext<A>,
     {
         let Engine {
-            analysis, body, mut entry_sets, tcx, apply_trans_for_block, pass_name, ..
+            mut analysis,
+            body,
+            mut entry_sets,
+            tcx,
+            apply_trans_for_block,
+            pass_name,
+            ..
         } = self;
 
         let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len());
@@ -203,11 +265,13 @@ where
             // Apply the block transfer function, using the cached one if it exists.
             match &apply_trans_for_block {
                 Some(apply) => apply(bb, &mut state),
-                None => A::Direction::apply_effects_in_block(&analysis, &mut state, bb, bb_data),
+                None => {
+                    A::Direction::apply_effects_in_block(&mut analysis, &mut state, bb, bb_data)
+                }
             }
 
             A::Direction::join_state_into_successors_of(
-                &analysis,
+                &mut analysis,
                 tcx,
                 body,
                 &mut state,
@@ -221,9 +285,9 @@ where
             );
         }
 
-        let results = Results { analysis, entry_sets };
+        let mut results = Results { analysis, entry_sets, _marker: PhantomData };
 
-        let res = write_graphviz_results(tcx, &body, &results, pass_name);
+        let res = write_graphviz_results(tcx, body, &mut results, pass_name);
         if let Err(e) = res {
             error!("Failed to write graphviz dataflow results: {}", e);
         }
@@ -239,7 +303,7 @@ where
 fn write_graphviz_results<'tcx, A>(
     tcx: TyCtxt<'tcx>,
     body: &mir::Body<'tcx>,
-    results: &Results<'tcx, A>,
+    results: &mut Results<'tcx, A>,
     pass_name: Option<&'static str>,
 ) -> std::io::Result<()>
 where
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index 707729f8f21..e331533c371 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -1,6 +1,7 @@
 //! A helpful diagram for debugging dataflow problems.
 
 use std::borrow::Cow;
+use std::cell::RefCell;
 use std::sync::OnceLock;
 use std::{io, ops, str};
 
@@ -28,23 +29,27 @@ impl OutputStyle {
     }
 }
 
-pub struct Formatter<'a, 'tcx, A>
+pub struct Formatter<'res, 'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
-    body: &'a Body<'tcx>,
-    results: &'a Results<'tcx, A>,
+    body: &'mir Body<'tcx>,
+    results: RefCell<&'res mut Results<'tcx, A>>,
     style: OutputStyle,
     reachable: BitSet<BasicBlock>,
 }
 
-impl<'a, 'tcx, A> Formatter<'a, 'tcx, A>
+impl<'res, 'mir, 'tcx, A> Formatter<'res, 'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
-    pub fn new(body: &'a Body<'tcx>, results: &'a Results<'tcx, A>, style: OutputStyle) -> Self {
+    pub fn new(
+        body: &'mir Body<'tcx>,
+        results: &'res mut Results<'tcx, A>,
+        style: OutputStyle,
+    ) -> Self {
         let reachable = mir::traversal::reachable_as_bitset(body);
-        Formatter { body, results, style, reachable }
+        Formatter { body, results: results.into(), style, reachable }
     }
 }
 
@@ -64,7 +69,7 @@ fn dataflow_successors(body: &Body<'_>, bb: BasicBlock) -> Vec<CfgEdge> {
         .collect()
 }
 
-impl<'tcx, A> dot::Labeller<'_> for Formatter<'_, 'tcx, A>
+impl<'tcx, A> dot::Labeller<'_> for Formatter<'_, '_, 'tcx, A>
 where
     A: Analysis<'tcx>,
     A::Domain: DebugWithContext<A>,
@@ -83,13 +88,14 @@ where
 
     fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> {
         let mut label = Vec::new();
+        let mut results = self.results.borrow_mut();
         let mut fmt = BlockFormatter {
-            results: ResultsRefCursor::new(self.body, self.results),
+            results: results.as_results_cursor(self.body),
             style: self.style,
             bg: Background::Light,
         };
 
-        fmt.write_node_label(&mut label, self.body, *block).unwrap();
+        fmt.write_node_label(&mut label, *block).unwrap();
         dot::LabelText::html(String::from_utf8(label).unwrap())
     }
 
@@ -103,7 +109,7 @@ where
     }
 }
 
-impl<'a, 'tcx, A> dot::GraphWalk<'a> for Formatter<'a, 'tcx, A>
+impl<'mir, 'tcx, A> dot::GraphWalk<'mir> for Formatter<'_, 'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
@@ -137,16 +143,16 @@ where
     }
 }
 
-struct BlockFormatter<'a, 'tcx, A>
+struct BlockFormatter<'res, 'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
-    results: ResultsRefCursor<'a, 'a, 'tcx, A>,
+    results: ResultsRefCursor<'res, 'mir, 'tcx, A>,
     bg: Background,
     style: OutputStyle,
 }
 
-impl<'a, 'tcx, A> BlockFormatter<'a, 'tcx, A>
+impl<'res, 'mir, 'tcx, A> BlockFormatter<'res, 'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
     A::Domain: DebugWithContext<A>,
@@ -159,12 +165,7 @@ where
         bg
     }
 
-    fn write_node_label(
-        &mut self,
-        w: &mut impl io::Write,
-        body: &'a Body<'tcx>,
-        block: BasicBlock,
-    ) -> io::Result<()> {
+    fn write_node_label(&mut self, w: &mut impl io::Write, block: BasicBlock) -> io::Result<()> {
         //   Sample output:
         //   +-+-----------------------------------------------+
         // A |                      bb4                        |
@@ -215,11 +216,11 @@ where
         self.write_row_with_full_state(w, "", "(on start)")?;
 
         // D + E: Statement and terminator transfer functions
-        self.write_statements_and_terminator(w, body, block)?;
+        self.write_statements_and_terminator(w, block)?;
 
         // F: State at end of block
 
-        let terminator = body[block].terminator();
+        let terminator = self.results.body()[block].terminator();
 
         // Write the full dataflow state immediately after the terminator if it differs from the
         // state at block entry.
@@ -389,10 +390,14 @@ where
     fn write_statements_and_terminator(
         &mut self,
         w: &mut impl io::Write,
-        body: &'a Body<'tcx>,
         block: BasicBlock,
     ) -> io::Result<()> {
-        let diffs = StateDiffCollector::run(body, block, self.results.results(), self.style);
+        let diffs = StateDiffCollector::run(
+            self.results.body(),
+            block,
+            self.results.mut_results(),
+            self.style,
+        );
 
         let mut diffs_before = diffs.before.map(|v| v.into_iter());
         let mut diffs_after = diffs.after.into_iter();
@@ -401,7 +406,7 @@ where
             if A::Direction::IS_FORWARD { it.next().unwrap() } else { it.next_back().unwrap() }
         };
 
-        for (i, statement) in body[block].statements.iter().enumerate() {
+        for (i, statement) in self.results.body()[block].statements.iter().enumerate() {
             let statement_str = format!("{statement:?}");
             let index_str = format!("{i}");
 
@@ -423,7 +428,7 @@ where
         assert!(diffs_after.is_empty());
         assert!(diffs_before.as_ref().map_or(true, ExactSizeIterator::is_empty));
 
-        let terminator = body[block].terminator();
+        let terminator = self.results.body()[block].terminator();
         let mut terminator_str = String::new();
         terminator.kind.fmt_head(&mut terminator_str).unwrap();
 
@@ -492,29 +497,24 @@ where
     }
 }
 
-struct StateDiffCollector<'a, 'tcx, A>
-where
-    A: Analysis<'tcx>,
-{
-    analysis: &'a A,
-    prev_state: A::Domain,
+struct StateDiffCollector<D> {
+    prev_state: D,
     before: Option<Vec<String>>,
     after: Vec<String>,
 }
 
-impl<'a, 'tcx, A> StateDiffCollector<'a, 'tcx, A>
-where
-    A: Analysis<'tcx>,
-    A::Domain: DebugWithContext<A>,
-{
-    fn run(
-        body: &'a mir::Body<'tcx>,
+impl<D> StateDiffCollector<D> {
+    fn run<'tcx, A>(
+        body: &mir::Body<'tcx>,
         block: BasicBlock,
-        results: &'a Results<'tcx, A>,
+        results: &mut Results<'tcx, A>,
         style: OutputStyle,
-    ) -> Self {
+    ) -> Self
+    where
+        A: Analysis<'tcx, Domain = D>,
+        D: DebugWithContext<A>,
+    {
         let mut collector = StateDiffCollector {
-            analysis: &results.analysis,
             prev_state: results.analysis.bottom_value(body),
             after: vec![],
             before: (style == OutputStyle::BeforeAndAfter).then_some(vec![]),
@@ -525,7 +525,7 @@ where
     }
 }
 
-impl<'a, 'tcx, A> ResultsVisitor<'a, 'tcx> for StateDiffCollector<'a, 'tcx, A>
+impl<'tcx, A> ResultsVisitor<'_, 'tcx, Results<'tcx, A>> for StateDiffCollector<A::Domain>
 where
     A: Analysis<'tcx>,
     A::Domain: DebugWithContext<A>,
@@ -534,6 +534,7 @@ where
 
     fn visit_block_start(
         &mut self,
+        _results: &Results<'tcx, A>,
         state: &Self::FlowState,
         _block_data: &mir::BasicBlockData<'tcx>,
         _block: BasicBlock,
@@ -545,6 +546,7 @@ where
 
     fn visit_block_end(
         &mut self,
+        _results: &Results<'tcx, A>,
         state: &Self::FlowState,
         _block_data: &mir::BasicBlockData<'tcx>,
         _block: BasicBlock,
@@ -556,45 +558,49 @@ where
 
     fn visit_statement_before_primary_effect(
         &mut self,
+        results: &Results<'tcx, A>,
         state: &Self::FlowState,
         _statement: &mir::Statement<'tcx>,
         _location: Location,
     ) {
         if let Some(before) = self.before.as_mut() {
-            before.push(diff_pretty(state, &self.prev_state, self.analysis));
+            before.push(diff_pretty(state, &self.prev_state, &results.analysis));
             self.prev_state.clone_from(state)
         }
     }
 
     fn visit_statement_after_primary_effect(
         &mut self,
+        results: &Results<'tcx, A>,
         state: &Self::FlowState,
         _statement: &mir::Statement<'tcx>,
         _location: Location,
     ) {
-        self.after.push(diff_pretty(state, &self.prev_state, self.analysis));
+        self.after.push(diff_pretty(state, &self.prev_state, &results.analysis));
         self.prev_state.clone_from(state)
     }
 
     fn visit_terminator_before_primary_effect(
         &mut self,
+        results: &Results<'tcx, A>,
         state: &Self::FlowState,
         _terminator: &mir::Terminator<'tcx>,
         _location: Location,
     ) {
         if let Some(before) = self.before.as_mut() {
-            before.push(diff_pretty(state, &self.prev_state, self.analysis));
+            before.push(diff_pretty(state, &self.prev_state, &results.analysis));
             self.prev_state.clone_from(state)
         }
     }
 
     fn visit_terminator_after_primary_effect(
         &mut self,
+        results: &Results<'tcx, A>,
         state: &Self::FlowState,
         _terminator: &mir::Terminator<'tcx>,
         _location: Location,
     ) {
-        self.after.push(diff_pretty(state, &self.prev_state, self.analysis));
+        self.after.push(diff_pretty(state, &self.prev_state, &results.analysis));
         self.prev_state.clone_from(state)
     }
 }
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index f2263007f6f..e5e9c1507ba 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -45,9 +45,9 @@ pub mod graphviz;
 pub mod lattice;
 mod visitor;
 
-pub use self::cursor::{ResultsCursor, ResultsRefCursor};
+pub use self::cursor::{ResultsClonedCursor, ResultsCursor, ResultsRefCursor};
 pub use self::direction::{Backward, Direction, Forward};
-pub use self::engine::{Engine, Results};
+pub use self::engine::{Engine, EntrySets, Results, ResultsCloned};
 pub use self::lattice::{JoinSemiLattice, MeetSemiLattice};
 pub use self::visitor::{visit_results, ResultsVisitable, ResultsVisitor};
 
@@ -146,7 +146,7 @@ pub trait AnalysisDomain<'tcx> {
 pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
     /// Updates the current dataflow state with the effect of evaluating a statement.
     fn apply_statement_effect(
-        &self,
+        &mut self,
         state: &mut Self::Domain,
         statement: &mir::Statement<'tcx>,
         location: Location,
@@ -159,7 +159,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
     /// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule,
     /// analyses should not implement this without also implementing `apply_statement_effect`.
     fn apply_before_statement_effect(
-        &self,
+        &mut self,
         _state: &mut Self::Domain,
         _statement: &mir::Statement<'tcx>,
         _location: Location,
@@ -173,7 +173,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
     /// `InitializedPlaces` analyses, the return place for a function call is not marked as
     /// initialized here.
     fn apply_terminator_effect(
-        &self,
+        &mut self,
         state: &mut Self::Domain,
         terminator: &mir::Terminator<'tcx>,
         location: Location,
@@ -186,7 +186,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
     /// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule,
     /// analyses should not implement this without also implementing `apply_terminator_effect`.
     fn apply_before_terminator_effect(
-        &self,
+        &mut self,
         _state: &mut Self::Domain,
         _terminator: &mir::Terminator<'tcx>,
         _location: Location,
@@ -201,7 +201,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
     /// This is separate from `apply_terminator_effect` to properly track state across unwind
     /// edges.
     fn apply_call_return_effect(
-        &self,
+        &mut self,
         state: &mut Self::Domain,
         block: BasicBlock,
         return_places: CallReturnPlaces<'_, 'tcx>,
@@ -214,7 +214,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
     ///
     /// By default, no effects happen.
     fn apply_yield_resume_effect(
-        &self,
+        &mut self,
         _state: &mut Self::Domain,
         _resume_block: BasicBlock,
         _resume_place: mir::Place<'tcx>,
@@ -235,7 +235,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
     /// engine doesn't need to clone the exit state for a block unless
     /// `SwitchIntEdgeEffects::apply` is actually called.
     fn apply_switch_int_edge_effects(
-        &self,
+        &mut self,
         _block: BasicBlock,
         _discr: &mir::Operand<'tcx>,
         _apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
@@ -269,6 +269,21 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
     }
 }
 
+/// Defines an `Analysis` which can be cloned for use in multiple `ResultsCursor`s or
+/// `ResultsVisitor`s. Note this need not be a full clone, only enough of one to be used with a new
+/// `ResultsCursor` or `ResultsVisitor`
+pub trait CloneAnalysis {
+    fn clone_analysis(&self) -> Self;
+}
+impl<'tcx, A> CloneAnalysis for A
+where
+    A: Analysis<'tcx> + Copy,
+{
+    fn clone_analysis(&self) -> Self {
+        *self
+    }
+}
+
 /// A gen/kill dataflow problem.
 ///
 /// Each method in this trait has a corresponding one in `Analysis`. However, these methods only
@@ -282,7 +297,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
 
     /// See `Analysis::apply_statement_effect`.
     fn statement_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         statement: &mir::Statement<'tcx>,
         location: Location,
@@ -290,7 +305,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
 
     /// See `Analysis::apply_before_statement_effect`.
     fn before_statement_effect(
-        &self,
+        &mut self,
         _trans: &mut impl GenKill<Self::Idx>,
         _statement: &mir::Statement<'tcx>,
         _location: Location,
@@ -299,7 +314,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
 
     /// See `Analysis::apply_terminator_effect`.
     fn terminator_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         terminator: &mir::Terminator<'tcx>,
         location: Location,
@@ -307,7 +322,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
 
     /// See `Analysis::apply_before_terminator_effect`.
     fn before_terminator_effect(
-        &self,
+        &mut self,
         _trans: &mut impl GenKill<Self::Idx>,
         _terminator: &mir::Terminator<'tcx>,
         _location: Location,
@@ -318,7 +333,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
 
     /// See `Analysis::apply_call_return_effect`.
     fn call_return_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         block: BasicBlock,
         return_places: CallReturnPlaces<'_, 'tcx>,
@@ -326,7 +341,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
 
     /// See `Analysis::apply_yield_resume_effect`.
     fn yield_resume_effect(
-        &self,
+        &mut self,
         _trans: &mut impl GenKill<Self::Idx>,
         _resume_block: BasicBlock,
         _resume_place: mir::Place<'tcx>,
@@ -335,7 +350,7 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
 
     /// See `Analysis::apply_switch_int_edge_effects`.
     fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
-        &self,
+        &mut self,
         _block: BasicBlock,
         _discr: &mir::Operand<'tcx>,
         _edge_effects: &mut impl SwitchIntEdgeEffects<G>,
@@ -349,7 +364,7 @@ where
     A::Domain: GenKill<A::Idx> + BitSetExt<A::Idx>,
 {
     fn apply_statement_effect(
-        &self,
+        &mut self,
         state: &mut A::Domain,
         statement: &mir::Statement<'tcx>,
         location: Location,
@@ -358,7 +373,7 @@ where
     }
 
     fn apply_before_statement_effect(
-        &self,
+        &mut self,
         state: &mut A::Domain,
         statement: &mir::Statement<'tcx>,
         location: Location,
@@ -367,7 +382,7 @@ where
     }
 
     fn apply_terminator_effect(
-        &self,
+        &mut self,
         state: &mut A::Domain,
         terminator: &mir::Terminator<'tcx>,
         location: Location,
@@ -376,7 +391,7 @@ where
     }
 
     fn apply_before_terminator_effect(
-        &self,
+        &mut self,
         state: &mut A::Domain,
         terminator: &mir::Terminator<'tcx>,
         location: Location,
@@ -387,7 +402,7 @@ where
     /* Edge-specific effects */
 
     fn apply_call_return_effect(
-        &self,
+        &mut self,
         state: &mut A::Domain,
         block: BasicBlock,
         return_places: CallReturnPlaces<'_, 'tcx>,
@@ -396,7 +411,7 @@ where
     }
 
     fn apply_yield_resume_effect(
-        &self,
+        &mut self,
         state: &mut A::Domain,
         resume_block: BasicBlock,
         resume_place: mir::Place<'tcx>,
@@ -405,7 +420,7 @@ where
     }
 
     fn apply_switch_int_edge_effects(
-        &self,
+        &mut self,
         block: BasicBlock,
         discr: &mir::Operand<'tcx>,
         edge_effects: &mut impl SwitchIntEdgeEffects<A::Domain>,
diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs
index 0fed305b930..45c2fe55aca 100644
--- a/compiler/rustc_mir_dataflow/src/framework/tests.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs
@@ -179,7 +179,7 @@ impl<'tcx, D: Direction> AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> {
 
 impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
     fn apply_statement_effect(
-        &self,
+        &mut self,
         state: &mut Self::Domain,
         _statement: &mir::Statement<'tcx>,
         location: Location,
@@ -189,7 +189,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
     }
 
     fn apply_before_statement_effect(
-        &self,
+        &mut self,
         state: &mut Self::Domain,
         _statement: &mir::Statement<'tcx>,
         location: Location,
@@ -199,7 +199,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
     }
 
     fn apply_terminator_effect(
-        &self,
+        &mut self,
         state: &mut Self::Domain,
         _terminator: &mir::Terminator<'tcx>,
         location: Location,
@@ -209,7 +209,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
     }
 
     fn apply_before_terminator_effect(
-        &self,
+        &mut self,
         state: &mut Self::Domain,
         _terminator: &mir::Terminator<'tcx>,
         location: Location,
@@ -219,7 +219,7 @@ impl<'tcx, D: Direction> Analysis<'tcx> for MockAnalysis<'tcx, D> {
     }
 
     fn apply_call_return_effect(
-        &self,
+        &mut self,
         _state: &mut Self::Domain,
         _block: BasicBlock,
         _return_places: CallReturnPlaces<'_, 'tcx>,
@@ -266,7 +266,8 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
     let body = analysis.body;
 
     let mut cursor =
-        Results { entry_sets: analysis.mock_entry_sets(), analysis }.into_results_cursor(body);
+        Results { entry_sets: analysis.mock_entry_sets(), analysis, _marker: PhantomData }
+            .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 75b4e150a8a..76a72982781 100644
--- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
@@ -1,16 +1,18 @@
+use std::borrow::Borrow;
+
 use rustc_middle::mir::{self, BasicBlock, Location};
 
-use super::{Analysis, Direction, Results};
+use super::{Analysis, Direction, EntrySets, Results};
 
 /// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the
 /// dataflow state at that location.
-pub fn visit_results<'mir, 'tcx, F, V>(
+pub fn visit_results<'mir, 'tcx, F, R>(
     body: &'mir mir::Body<'tcx>,
     blocks: impl IntoIterator<Item = BasicBlock>,
-    results: &V,
-    vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = F>,
+    results: &mut R,
+    vis: &mut impl ResultsVisitor<'mir, 'tcx, R, FlowState = F>,
 ) where
-    V: ResultsVisitable<'tcx, FlowState = F>,
+    R: ResultsVisitable<'tcx, FlowState = F>,
 {
     let mut state = results.new_flow_state(body);
 
@@ -22,15 +24,18 @@ pub fn visit_results<'mir, 'tcx, F, V>(
         assert!(reachable_blocks.contains(block));
 
         let block_data = &body[block];
-        V::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
+        R::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
     }
 }
 
-pub trait ResultsVisitor<'mir, 'tcx> {
+/// A visitor over the results of an `Analysis`. The type parameter `R` is the results type being
+/// visited.
+pub trait ResultsVisitor<'mir, 'tcx, R> {
     type FlowState;
 
     fn visit_block_start(
         &mut self,
+        _results: &R,
         _state: &Self::FlowState,
         _block_data: &'mir mir::BasicBlockData<'tcx>,
         _block: BasicBlock,
@@ -41,6 +46,7 @@ pub trait ResultsVisitor<'mir, 'tcx> {
     /// its `statement_effect`.
     fn visit_statement_before_primary_effect(
         &mut self,
+        _results: &R,
         _state: &Self::FlowState,
         _statement: &'mir mir::Statement<'tcx>,
         _location: Location,
@@ -51,6 +57,7 @@ pub trait ResultsVisitor<'mir, 'tcx> {
     /// statement applied to `state`.
     fn visit_statement_after_primary_effect(
         &mut self,
+        _results: &R,
         _state: &Self::FlowState,
         _statement: &'mir mir::Statement<'tcx>,
         _location: Location,
@@ -61,6 +68,7 @@ pub trait ResultsVisitor<'mir, 'tcx> {
     /// its `terminator_effect`.
     fn visit_terminator_before_primary_effect(
         &mut self,
+        _results: &R,
         _state: &Self::FlowState,
         _terminator: &'mir mir::Terminator<'tcx>,
         _location: Location,
@@ -73,6 +81,7 @@ pub trait ResultsVisitor<'mir, 'tcx> {
     /// The `call_return_effect` (if one exists) will *not* be applied to `state`.
     fn visit_terminator_after_primary_effect(
         &mut self,
+        _results: &R,
         _state: &Self::FlowState,
         _terminator: &'mir mir::Terminator<'tcx>,
         _location: Location,
@@ -81,6 +90,7 @@ pub trait ResultsVisitor<'mir, 'tcx> {
 
     fn visit_block_end(
         &mut self,
+        _results: &R,
         _state: &Self::FlowState,
         _block_data: &'mir mir::BasicBlockData<'tcx>,
         _block: BasicBlock,
@@ -105,37 +115,38 @@ pub trait ResultsVisitable<'tcx> {
     fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock);
 
     fn reconstruct_before_statement_effect(
-        &self,
+        &mut self,
         state: &mut Self::FlowState,
         statement: &mir::Statement<'tcx>,
         location: Location,
     );
 
     fn reconstruct_statement_effect(
-        &self,
+        &mut self,
         state: &mut Self::FlowState,
         statement: &mir::Statement<'tcx>,
         location: Location,
     );
 
     fn reconstruct_before_terminator_effect(
-        &self,
+        &mut self,
         state: &mut Self::FlowState,
         terminator: &mir::Terminator<'tcx>,
         location: Location,
     );
 
     fn reconstruct_terminator_effect(
-        &self,
+        &mut self,
         state: &mut Self::FlowState,
         terminator: &mir::Terminator<'tcx>,
         location: Location,
     );
 }
 
-impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A>
+impl<'tcx, A, E> ResultsVisitable<'tcx> for Results<'tcx, A, E>
 where
     A: Analysis<'tcx>,
+    E: Borrow<EntrySets<'tcx, A>>,
 {
     type FlowState = A::Domain;
 
@@ -146,11 +157,11 @@ where
     }
 
     fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) {
-        state.clone_from(&self.entry_set_for_block(block));
+        state.clone_from(self.entry_set_for_block(block));
     }
 
     fn reconstruct_before_statement_effect(
-        &self,
+        &mut self,
         state: &mut Self::FlowState,
         stmt: &mir::Statement<'tcx>,
         loc: Location,
@@ -159,7 +170,7 @@ where
     }
 
     fn reconstruct_statement_effect(
-        &self,
+        &mut self,
         state: &mut Self::FlowState,
         stmt: &mir::Statement<'tcx>,
         loc: Location,
@@ -168,7 +179,7 @@ where
     }
 
     fn reconstruct_before_terminator_effect(
-        &self,
+        &mut self,
         state: &mut Self::FlowState,
         term: &mir::Terminator<'tcx>,
         loc: Location,
@@ -177,7 +188,7 @@ where
     }
 
     fn reconstruct_terminator_effect(
-        &self,
+        &mut self,
         state: &mut Self::FlowState,
         term: &mir::Terminator<'tcx>,
         loc: Location,
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index 92d30f254a6..b88ed32b687 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -10,6 +10,7 @@ use rustc_middle::mir::*;
 /// 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 generators.
+#[derive(Clone, Copy)]
 pub struct MaybeBorrowedLocals;
 
 impl MaybeBorrowedLocals {
@@ -36,7 +37,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
     type Idx = Local;
 
     fn statement_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         statement: &mir::Statement<'tcx>,
         location: Location,
@@ -45,7 +46,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
     }
 
     fn terminator_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         terminator: &mir::Terminator<'tcx>,
         location: Location,
@@ -54,7 +55,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
     }
 
     fn call_return_effect(
-        &self,
+        &mut self,
         _trans: &mut impl GenKill<Self::Idx>,
         _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 aeca0073304..56cd18cf711 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -21,6 +21,7 @@ use crate::{Analysis, AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKi
 /// [`MaybeBorrowedLocals`]: super::MaybeBorrowedLocals
 /// [flow-test]: https://github.com/rust-lang/rust/blob/a08c47310c7d49cbdc5d7afb38408ba519967ecd/src/test/ui/mir-dataflow/liveness-ptr.rs
 /// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis
+#[derive(Clone, Copy)]
 pub struct MaybeLiveLocals;
 
 impl<'tcx> AnalysisDomain<'tcx> for MaybeLiveLocals {
@@ -43,7 +44,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals {
     type Idx = Local;
 
     fn statement_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         statement: &mir::Statement<'tcx>,
         location: Location,
@@ -52,7 +53,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals {
     }
 
     fn terminator_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         terminator: &mir::Terminator<'tcx>,
         location: Location,
@@ -61,7 +62,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals {
     }
 
     fn call_return_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         _block: mir::BasicBlock,
         return_places: CallReturnPlaces<'_, 'tcx>,
@@ -74,7 +75,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals {
     }
 
     fn yield_resume_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         _resume_block: mir::BasicBlock,
         resume_place: mir::Place<'tcx>,
@@ -216,6 +217,7 @@ impl DefUse {
 /// This is basically written for dead store elimination and nothing else.
 ///
 /// All of the caveats of `MaybeLiveLocals` apply.
+#[derive(Clone, Copy)]
 pub struct MaybeTransitiveLiveLocals<'a> {
     always_live: &'a BitSet<Local>,
 }
@@ -248,7 +250,7 @@ impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a> {
 
 impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
     fn apply_statement_effect(
-        &self,
+        &mut self,
         trans: &mut Self::Domain,
         statement: &mir::Statement<'tcx>,
         location: Location,
@@ -283,7 +285,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
     }
 
     fn apply_terminator_effect(
-        &self,
+        &mut self,
         trans: &mut Self::Domain,
         terminator: &mir::Terminator<'tcx>,
         location: Location,
@@ -292,7 +294,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
     }
 
     fn apply_call_return_effect(
-        &self,
+        &mut self,
         trans: &mut Self::Domain,
         _block: mir::BasicBlock,
         return_places: CallReturnPlaces<'_, 'tcx>,
@@ -305,7 +307,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
     }
 
     fn apply_yield_resume_effect(
-        &self,
+        &mut self,
         trans: &mut Self::Domain,
         _resume_block: mir::BasicBlock,
         resume_place: mir::Place<'tcx>,
diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs
index 171db6965ac..98cec1c6760 100644
--- a/compiler/rustc_mir_dataflow/src/impls/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs
@@ -306,7 +306,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
     type Idx = MovePathIndex;
 
     fn statement_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         statement: &mir::Statement<'tcx>,
         location: Location,
@@ -329,7 +329,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
     }
 
     fn terminator_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         terminator: &mir::Terminator<'tcx>,
         location: Location,
@@ -351,7 +351,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
     }
 
     fn call_return_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         _block: mir::BasicBlock,
         return_places: CallReturnPlaces<'_, 'tcx>,
@@ -372,7 +372,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
     }
 
     fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
-        &self,
+        &mut self,
         block: mir::BasicBlock,
         discr: &mir::Operand<'tcx>,
         edge_effects: &mut impl SwitchIntEdgeEffects<G>,
@@ -442,7 +442,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
     type Idx = MovePathIndex;
 
     fn statement_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         _statement: &mir::Statement<'tcx>,
         location: Location,
@@ -456,7 +456,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
     }
 
     fn terminator_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         _terminator: &mir::Terminator<'tcx>,
         location: Location,
@@ -467,7 +467,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
     }
 
     fn call_return_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         _block: mir::BasicBlock,
         return_places: CallReturnPlaces<'_, 'tcx>,
@@ -488,7 +488,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
     }
 
     fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
-        &self,
+        &mut self,
         block: mir::BasicBlock,
         discr: &mir::Operand<'tcx>,
         edge_effects: &mut impl SwitchIntEdgeEffects<G>,
@@ -562,7 +562,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
     type Idx = MovePathIndex;
 
     fn statement_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         _statement: &mir::Statement<'tcx>,
         location: Location,
@@ -573,7 +573,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
     }
 
     fn terminator_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         _terminator: &mir::Terminator<'tcx>,
         location: Location,
@@ -584,7 +584,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
     }
 
     fn call_return_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         _block: mir::BasicBlock,
         return_places: CallReturnPlaces<'_, 'tcx>,
@@ -627,7 +627,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
 
     #[instrument(skip(self, trans), level = "debug")]
     fn statement_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         stmt: &mir::Statement<'tcx>,
         location: Location,
@@ -651,7 +651,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
 
     #[instrument(skip(self, trans, _terminator), level = "debug")]
     fn terminator_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         _terminator: &mir::Terminator<'tcx>,
         location: Location,
@@ -672,7 +672,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
     }
 
     fn call_return_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         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 463ce083a64..666c8d50a8a 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -1,10 +1,9 @@
 pub use super::*;
 
-use crate::{CallReturnPlaces, GenKill, Results, ResultsRefCursor};
+use crate::{CallReturnPlaces, GenKill, ResultsClonedCursor};
 use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use std::borrow::Cow;
-use std::cell::RefCell;
 
 #[derive(Clone)]
 pub struct MaybeStorageLive<'a> {
@@ -17,6 +16,12 @@ impl<'a> MaybeStorageLive<'a> {
     }
 }
 
+impl crate::CloneAnalysis for MaybeStorageLive<'_> {
+    fn clone_analysis(&self) -> Self {
+        self.clone()
+    }
+}
+
 impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> {
     type Domain = BitSet<Local>;
 
@@ -43,7 +48,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
     type Idx = Local;
 
     fn statement_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         stmt: &mir::Statement<'tcx>,
         _: Location,
@@ -56,7 +61,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
     }
 
     fn terminator_effect(
-        &self,
+        &mut self,
         _trans: &mut impl GenKill<Self::Idx>,
         _: &mir::Terminator<'tcx>,
         _: Location,
@@ -65,7 +70,7 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
     }
 
     fn call_return_effect(
-        &self,
+        &mut self,
         _trans: &mut impl GenKill<Self::Idx>,
         _block: BasicBlock,
         _return_places: CallReturnPlaces<'_, 'tcx>,
@@ -110,7 +115,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead {
     type Idx = Local;
 
     fn statement_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         stmt: &mir::Statement<'tcx>,
         _: Location,
@@ -123,7 +128,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead {
     }
 
     fn terminator_effect(
-        &self,
+        &mut self,
         _trans: &mut impl GenKill<Self::Idx>,
         _: &mir::Terminator<'tcx>,
         _: Location,
@@ -132,7 +137,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead {
     }
 
     fn call_return_effect(
-        &self,
+        &mut self,
         _trans: &mut impl GenKill<Self::Idx>,
         _block: BasicBlock,
         _return_places: CallReturnPlaces<'_, 'tcx>,
@@ -141,28 +146,28 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead {
     }
 }
 
-type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>;
+type BorrowedLocalsResults<'res, 'mir, 'tcx> =
+    ResultsClonedCursor<'res, 'mir, 'tcx, MaybeBorrowedLocals>;
 
 /// 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> {
-    body: &'mir Body<'tcx>,
-    borrowed_locals: RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
+pub struct MaybeRequiresStorage<'res, 'mir, 'tcx> {
+    borrowed_locals: BorrowedLocalsResults<'res, 'mir, 'tcx>,
 }
 
-impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
-    pub fn new(
-        body: &'mir Body<'tcx>,
-        borrowed_locals: &'mir Results<'tcx, MaybeBorrowedLocals>,
-    ) -> Self {
-        MaybeRequiresStorage {
-            body,
-            borrowed_locals: RefCell::new(ResultsRefCursor::new(&body, borrowed_locals)),
-        }
+impl<'res, 'mir, 'tcx> MaybeRequiresStorage<'res, 'mir, 'tcx> {
+    pub fn new(borrowed_locals: BorrowedLocalsResults<'res, 'mir, 'tcx>) -> Self {
+        MaybeRequiresStorage { borrowed_locals }
+    }
+}
+
+impl crate::CloneAnalysis for MaybeRequiresStorage<'_, '_, '_> {
+    fn clone_analysis(&self) -> Self {
+        Self { borrowed_locals: self.borrowed_locals.new_cursor() }
     }
 }
 
-impl<'mir, 'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
+impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> {
     type Domain = BitSet<Local>;
 
     const NAME: &'static str = "requires_storage";
@@ -181,17 +186,17 @@ impl<'mir, 'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx
     }
 }
 
-impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
+impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> {
     type Idx = Local;
 
     fn before_statement_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         stmt: &mir::Statement<'tcx>,
         loc: Location,
     ) {
         // If a place is borrowed in a statement, it needs storage for that statement.
-        self.borrowed_locals.borrow().analysis().statement_effect(trans, stmt, loc);
+        self.borrowed_locals.mut_analysis().statement_effect(trans, stmt, loc);
 
         match &stmt.kind {
             StatementKind::StorageDead(l) => trans.kill(*l),
@@ -218,7 +223,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
     }
 
     fn statement_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         _: &mir::Statement<'tcx>,
         loc: Location,
@@ -229,13 +234,13 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
     }
 
     fn before_terminator_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         terminator: &mir::Terminator<'tcx>,
         loc: Location,
     ) {
         // If a place is borrowed in a terminator, it needs storage for that terminator.
-        self.borrowed_locals.borrow().analysis().terminator_effect(trans, terminator, loc);
+        self.borrowed_locals.mut_analysis().terminator_effect(trans, terminator, loc);
 
         match &terminator.kind {
             TerminatorKind::Call { destination, .. } => {
@@ -282,7 +287,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
     }
 
     fn terminator_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         terminator: &mir::Terminator<'tcx>,
         loc: Location,
@@ -321,7 +326,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
     }
 
     fn call_return_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         _block: BasicBlock,
         return_places: CallReturnPlaces<'_, 'tcx>,
@@ -330,7 +335,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
     }
 
     fn yield_resume_effect(
-        &self,
+        &mut self,
         trans: &mut impl GenKill<Self::Idx>,
         _resume_block: BasicBlock,
         resume_place: mir::Place<'tcx>,
@@ -339,28 +344,28 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
     }
 }
 
-impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
+impl<'tcx> MaybeRequiresStorage<'_, '_, 'tcx> {
     /// Kill locals that are fully moved and have not been borrowed.
-    fn check_for_move(&self, trans: &mut impl GenKill<Local>, loc: Location) {
-        let mut visitor = MoveVisitor { trans, borrowed_locals: &self.borrowed_locals };
-        visitor.visit_location(&self.body, loc);
+    fn check_for_move(&mut self, trans: &mut impl GenKill<Local>, 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> {
-    borrowed_locals: &'a RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
+struct MoveVisitor<'a, 'res, 'mir, 'tcx, T> {
+    borrowed_locals: &'a mut BorrowedLocalsResults<'res, 'mir, 'tcx>,
     trans: &'a mut T,
 }
 
-impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx, T>
+impl<'tcx, T> Visitor<'tcx> for MoveVisitor<'_, '_, '_, 'tcx, T>
 where
     T: GenKill<Local>,
 {
     fn visit_local(&mut self, local: Local, context: PlaceContext, loc: Location) {
         if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
-            let mut borrowed_locals = self.borrowed_locals.borrow_mut();
-            borrowed_locals.seek_before_primary_effect(loc);
-            if !borrowed_locals.contains(local) {
+            self.borrowed_locals.seek_before_primary_effect(loc);
+            if !self.borrowed_locals.contains(local) {
                 self.trans.kill(local);
             }
         }
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index fc4efb943e6..3494a37c3cf 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -28,8 +28,9 @@ pub use self::drop_flag_effects::{
 };
 pub use self::framework::{
     fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, CallReturnPlaces,
-    Direction, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results, ResultsCursor,
-    ResultsRefCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects,
+    CloneAnalysis, Direction, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results,
+    ResultsCloned, ResultsClonedCursor, ResultsCursor, ResultsRefCursor, ResultsVisitable,
+    ResultsVisitor, SwitchIntEdgeEffects,
 };
 
 use self::move_paths::MoveData;
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 7cae68efbec..0cbc7442cf1 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -17,7 +17,7 @@ use crate::impls::{
 use crate::move_paths::{HasMoveData, MoveData};
 use crate::move_paths::{LookupResult, MovePathIndex};
 use crate::MoveDataParamEnv;
-use crate::{Analysis, JoinSemiLattice, Results, ResultsCursor};
+use crate::{Analysis, JoinSemiLattice, ResultsCursor};
 
 pub struct SanityCheck;
 
@@ -42,7 +42,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
                 .into_engine(tcx, body)
                 .iterate_to_fixpoint();
 
-            sanity_check_via_rustc_peek(tcx, body, &flow_inits);
+            sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body));
         }
 
         if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
@@ -50,7 +50,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
                 .into_engine(tcx, body)
                 .iterate_to_fixpoint();
 
-            sanity_check_via_rustc_peek(tcx, body, &flow_uninits);
+            sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
         }
 
         if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
@@ -58,13 +58,13 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
                 .into_engine(tcx, body)
                 .iterate_to_fixpoint();
 
-            sanity_check_via_rustc_peek(tcx, body, &flow_def_inits);
+            sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
         }
 
         if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
             let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
 
-            sanity_check_via_rustc_peek(tcx, body, &flow_liveness);
+            sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body));
         }
 
         if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() {
@@ -91,17 +91,14 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
 /// errors are not intended to be used for unit tests.)
 pub fn sanity_check_via_rustc_peek<'tcx, A>(
     tcx: TyCtxt<'tcx>,
-    body: &Body<'tcx>,
-    results: &Results<'tcx, A>,
+    mut cursor: ResultsCursor<'_, 'tcx, A>,
 ) where
     A: RustcPeekAt<'tcx>,
 {
-    let def_id = body.source.def_id();
+    let def_id = cursor.body().source.def_id();
     debug!("sanity_check_via_rustc_peek def_id: {:?}", def_id);
 
-    let mut cursor = ResultsCursor::new(body, results);
-
-    let peek_calls = body.basic_blocks.iter_enumerated().filter_map(|(bb, block_data)| {
+    let peek_calls = cursor.body().basic_blocks.iter_enumerated().filter_map(|(bb, block_data)| {
         PeekCall::from_terminator(tcx, block_data.terminator()).map(|call| (bb, block_data, call))
     });
 
@@ -132,8 +129,8 @@ pub fn sanity_check_via_rustc_peek<'tcx, A>(
             ) => {
                 let loc = Location { block: bb, statement_index };
                 cursor.seek_before_primary_effect(loc);
-                let state = cursor.get();
-                results.analysis.peek_at(tcx, *place, state, call);
+                let (state, analysis) = cursor.get_with_analysis();
+                analysis.peek_at(tcx, *place, state, call);
             }
 
             _ => {
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index b74d06e5ae8..5693e5a4a71 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -343,7 +343,7 @@ where
     T: ValueAnalysis<'tcx>,
 {
     fn apply_statement_effect(
-        &self,
+        &mut self,
         state: &mut Self::Domain,
         statement: &Statement<'tcx>,
         _location: Location,
@@ -354,7 +354,7 @@ where
     }
 
     fn apply_terminator_effect(
-        &self,
+        &mut self,
         state: &mut Self::Domain,
         terminator: &Terminator<'tcx>,
         _location: Location,
@@ -365,7 +365,7 @@ where
     }
 
     fn apply_call_return_effect(
-        &self,
+        &mut self,
         state: &mut Self::Domain,
         _block: BasicBlock,
         return_places: crate::CallReturnPlaces<'_, 'tcx>,
@@ -376,7 +376,7 @@ where
     }
 
     fn apply_switch_int_edge_effects(
-        &self,
+        &mut self,
         _block: BasicBlock,
         discr: &Operand<'tcx>,
         apply_edge_effects: &mut impl SwitchIntEdgeEffects<Self::Domain>,
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 7adfc9dff2a..78fb196358f 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -10,8 +10,12 @@ use rustc_middle::mir::visit::{MutVisitor, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_mir_dataflow::value_analysis::{Map, State, TrackElem, ValueAnalysis, ValueOrPlace};
-use rustc_mir_dataflow::{lattice::FlatSet, Analysis, ResultsVisitor, SwitchIntEdgeEffects};
+use rustc_mir_dataflow::value_analysis::{
+    Map, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace,
+};
+use rustc_mir_dataflow::{
+    lattice::FlatSet, Analysis, Results, ResultsVisitor, SwitchIntEdgeEffects,
+};
 use rustc_span::DUMMY_SP;
 use rustc_target::abi::{Align, FieldIdx, VariantIdx};
 
@@ -52,11 +56,11 @@ impl<'tcx> MirPass<'tcx> for DataflowConstProp {
 
         // Perform the actual dataflow analysis.
         let analysis = ConstAnalysis::new(tcx, body, map);
-        let results = debug_span!("analyze")
+        let mut results = debug_span!("analyze")
             .in_scope(|| analysis.wrap().into_engine(tcx, body).iterate_to_fixpoint());
 
         // Collect results and patch the body afterwards.
-        let mut visitor = CollectAndPatch::new(tcx, &results.analysis.0.map);
+        let mut visitor = CollectAndPatch::new(tcx);
         debug_span!("collect").in_scope(|| results.visit_reachable_with(body, &mut visitor));
         debug_span!("patch").in_scope(|| visitor.visit_body(body));
     }
@@ -387,9 +391,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
     }
 }
 
-struct CollectAndPatch<'tcx, 'map> {
+struct CollectAndPatch<'tcx> {
     tcx: TyCtxt<'tcx>,
-    map: &'map Map,
 
     /// For a given MIR location, this stores the values of the operands used by that location. In
     /// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are
@@ -400,9 +403,9 @@ struct CollectAndPatch<'tcx, 'map> {
     assignments: FxHashMap<Location, ScalarTy<'tcx>>,
 }
 
-impl<'tcx, 'map> CollectAndPatch<'tcx, 'map> {
-    fn new(tcx: TyCtxt<'tcx>, map: &'map Map) -> Self {
-        Self { tcx, map, before_effect: FxHashMap::default(), assignments: FxHashMap::default() }
+impl<'tcx> CollectAndPatch<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>) -> Self {
+        Self { tcx, before_effect: FxHashMap::default(), assignments: FxHashMap::default() }
     }
 
     fn make_operand(&self, scalar: ScalarTy<'tcx>) -> Operand<'tcx> {
@@ -414,18 +417,23 @@ impl<'tcx, 'map> CollectAndPatch<'tcx, 'map> {
     }
 }
 
-impl<'mir, 'tcx, 'map> ResultsVisitor<'mir, 'tcx> for CollectAndPatch<'tcx, 'map> {
+impl<'mir, 'tcx>
+    ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>>
+    for CollectAndPatch<'tcx>
+{
     type FlowState = State<FlatSet<ScalarTy<'tcx>>>;
 
     fn visit_statement_before_primary_effect(
         &mut self,
+        results: &Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
         state: &Self::FlowState,
         statement: &'mir Statement<'tcx>,
         location: Location,
     ) {
         match &statement.kind {
             StatementKind::Assign(box (_, rvalue)) => {
-                OperandCollector { state, visitor: self }.visit_rvalue(rvalue, location);
+                OperandCollector { state, visitor: self, map: &results.analysis.0.map }
+                    .visit_rvalue(rvalue, location);
             }
             _ => (),
         }
@@ -433,6 +441,7 @@ impl<'mir, 'tcx, 'map> ResultsVisitor<'mir, 'tcx> for CollectAndPatch<'tcx, 'map
 
     fn visit_statement_after_primary_effect(
         &mut self,
+        results: &Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
         state: &Self::FlowState,
         statement: &'mir Statement<'tcx>,
         location: Location,
@@ -441,30 +450,34 @@ impl<'mir, 'tcx, 'map> ResultsVisitor<'mir, 'tcx> for CollectAndPatch<'tcx, 'map
             StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(_)))) => {
                 // Don't overwrite the assignment if it already uses a constant (to keep the span).
             }
-            StatementKind::Assign(box (place, _)) => match state.get(place.as_ref(), self.map) {
-                FlatSet::Top => (),
-                FlatSet::Elem(value) => {
-                    self.assignments.insert(location, value);
-                }
-                FlatSet::Bottom => {
-                    // This assignment is either unreachable, or an uninitialized value is assigned.
+            StatementKind::Assign(box (place, _)) => {
+                match state.get(place.as_ref(), &results.analysis.0.map) {
+                    FlatSet::Top => (),
+                    FlatSet::Elem(value) => {
+                        self.assignments.insert(location, value);
+                    }
+                    FlatSet::Bottom => {
+                        // This assignment is either unreachable, or an uninitialized value is assigned.
+                    }
                 }
-            },
+            }
             _ => (),
         }
     }
 
     fn visit_terminator_before_primary_effect(
         &mut self,
+        results: &Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>,
         state: &Self::FlowState,
         terminator: &'mir Terminator<'tcx>,
         location: Location,
     ) {
-        OperandCollector { state, visitor: self }.visit_terminator(terminator, location);
+        OperandCollector { state, visitor: self, map: &results.analysis.0.map }
+            .visit_terminator(terminator, location);
     }
 }
 
-impl<'tcx, 'map> MutVisitor<'tcx> for CollectAndPatch<'tcx, 'map> {
+impl<'tcx> MutVisitor<'tcx> for CollectAndPatch<'tcx> {
     fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
         self.tcx
     }
@@ -496,14 +509,15 @@ impl<'tcx, 'map> MutVisitor<'tcx> for CollectAndPatch<'tcx, 'map> {
 
 struct OperandCollector<'tcx, 'map, 'a> {
     state: &'a State<FlatSet<ScalarTy<'tcx>>>,
-    visitor: &'a mut CollectAndPatch<'tcx, 'map>,
+    visitor: &'a mut CollectAndPatch<'tcx>,
+    map: &'map Map,
 }
 
 impl<'tcx, 'map, 'a> Visitor<'tcx> for OperandCollector<'tcx, 'map, 'a> {
     fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
         match operand {
             Operand::Copy(place) | Operand::Move(place) => {
-                match self.state.get(place.as_ref(), self.visitor.map) {
+                match self.state.get(place.as_ref(), self.map) {
                     FlatSet::Top => (),
                     FlatSet::Elem(value) => {
                         self.visitor.before_effect.insert((location, *place), value);
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index 891e446942e..98f5020e355 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -597,16 +597,15 @@ fn locals_live_across_suspend_points<'tcx>(
     let borrowed_locals_results =
         MaybeBorrowedLocals.into_engine(tcx, body_ref).pass_name("generator").iterate_to_fixpoint();
 
-    let mut borrowed_locals_cursor =
-        rustc_mir_dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results);
+    let mut borrowed_locals_cursor = borrowed_locals_results.cloned_results_cursor(body_ref);
 
     // Calculate the MIR locals that we actually need to keep storage around
     // for.
-    let requires_storage_results = MaybeRequiresStorage::new(body, &borrowed_locals_results)
-        .into_engine(tcx, body_ref)
-        .iterate_to_fixpoint();
-    let mut requires_storage_cursor =
-        rustc_mir_dataflow::ResultsCursor::new(body_ref, &requires_storage_results);
+    let mut requires_storage_results =
+        MaybeRequiresStorage::new(borrowed_locals_results.cloned_results_cursor(body))
+            .into_engine(tcx, body_ref)
+            .iterate_to_fixpoint();
+    let mut requires_storage_cursor = requires_storage_results.as_results_cursor(body_ref);
 
     // Calculate the liveness of MIR locals ignoring borrows.
     let mut liveness = MaybeLiveLocals
@@ -747,7 +746,7 @@ fn compute_storage_conflicts<'mir, 'tcx>(
     body: &'mir Body<'tcx>,
     saved_locals: &GeneratorSavedLocals,
     always_live_locals: BitSet<Local>,
-    requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
+    mut requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'_, 'mir, 'tcx>>,
 ) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> {
     assert_eq!(body.local_decls.len(), saved_locals.domain_size());
 
@@ -802,13 +801,14 @@ struct StorageConflictVisitor<'mir, 'tcx, 's> {
     local_conflicts: BitMatrix<Local, Local>,
 }
 
-impl<'mir, 'tcx> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx>
+impl<'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R>
     for StorageConflictVisitor<'mir, 'tcx, '_>
 {
     type FlowState = BitSet<Local>;
 
     fn visit_statement_before_primary_effect(
         &mut self,
+        _results: &R,
         state: &Self::FlowState,
         _statement: &'mir Statement<'tcx>,
         loc: Location,
@@ -818,6 +818,7 @@ impl<'mir, 'tcx> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx>
 
     fn visit_terminator_before_primary_effect(
         &mut self,
+        _results: &R,
         state: &Self::FlowState,
         _terminator: &'mir Terminator<'tcx>,
         loc: Location,