about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-12-05 02:36:50 +0000
committerbors <bors@rust-lang.org>2023-12-05 02:36:50 +0000
commit317d14a56cb8c748bf0e2f2afff89c2249ab4423 (patch)
tree4e37c37a8865e2c0eed21dcfb260b09944fbc081
parent25dca407519f4b03d96c416ea3075533a352ed05 (diff)
parente966c894179969e22d51982ac85da58e8b8862bb (diff)
downloadrust-317d14a56cb8c748bf0e2f2afff89c2249ab4423.tar.gz
rust-317d14a56cb8c748bf0e2f2afff89c2249ab4423.zip
Auto merge of #118230 - nnethercote:streamline-dataflow-cursors, r=cjgillot
Streamline MIR dataflow cursors

`rustc_mir_dataflow` has two kinds of results (`Results` and `ResultsCloned`) and three kinds of results cursor (`ResultsCursor`, `ResultsClonedCursor`, `ResultsRefCursor`). I found this quite confusing.

This PR removes `ResultsCloned`, `ResultsClonedCursor`, and `ResultsRefCursor`, leaving just `Results` and `ResultsCursor`. This makes the relevant code shorter and easier to read, and there is no performance penalty.

r? `@cjgillot`
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/cursor.rs103
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/engine.rs125
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs45
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs19
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/tests.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/visitor.rs7
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs37
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs3
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs14
9 files changed, 113 insertions, 243 deletions
diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
index c9bce80853d..815f2045942 100644
--- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
@@ -1,60 +1,14 @@
 //! Random access inspection of the results of a dataflow analysis.
 
-use crate::{framework::BitSetExt, CloneAnalysis};
+use crate::framework::BitSetExt;
 
-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, 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<'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>>;
+use super::{Analysis, Direction, Effect, EffectIndex, Results};
 
 /// Allows random access inspection of the results of a dataflow analysis.
 ///
@@ -62,15 +16,12 @@ pub type ResultsClonedCursor<'res, 'mir, 'tcx, A> =
 /// the same order as the `DIRECTION` of the analysis. In the worst case—when statements are
 /// visited in *reverse* order—performance will be quadratic in the number of statements in the
 /// block. The order in which basic blocks are inspected has no impact on performance.
-///
-/// A `ResultsCursor` can either own (the default) or borrow the dataflow results it inspects. The
-/// type of ownership is determined by `R` (see `ResultsRefCursor` above).
-pub struct ResultsCursor<'mir, 'tcx, A, R = Results<'tcx, A>>
+pub struct ResultsCursor<'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
     body: &'mir mir::Body<'tcx>,
-    results: R,
+    results: Results<'tcx, A>,
     state: A::Domain,
 
     pos: CursorPosition,
@@ -84,7 +35,7 @@ where
     reachable_blocks: BitSet<BasicBlock>,
 }
 
-impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
+impl<'mir, 'tcx, A> ResultsCursor<'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
@@ -99,30 +50,13 @@ where
     }
 
     /// Unwraps this cursor, returning the underlying `Results`.
-    pub fn into_results(self) -> R {
+    pub fn into_results(self) -> Results<'tcx, A> {
         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 {
-        let bottom_value = results.borrow().analysis.bottom_value(body);
+    pub fn new(body: &'mir mir::Body<'tcx>, results: Results<'tcx, A>) -> Self {
+        let bottom_value = results.analysis.bottom_value(body);
         ResultsCursor {
             body,
             results,
@@ -147,23 +81,23 @@ where
     }
 
     /// Returns the underlying `Results`.
-    pub fn results(&self) -> &Results<'tcx, A, R::EntrySets> {
-        self.results.borrow()
+    pub fn results(&self) -> &Results<'tcx, A> {
+        &self.results
     }
 
     /// Returns the underlying `Results`.
-    pub fn mut_results(&mut self) -> &mut Results<'tcx, A, R::EntrySets> {
-        self.results.borrow_mut()
+    pub fn mut_results(&mut self) -> &mut Results<'tcx, A> {
+        &mut self.results
     }
 
     /// Returns the `Analysis` used to generate the underlying `Results`.
     pub fn analysis(&self) -> &A {
-        &self.results.borrow().analysis
+        &self.results.analysis
     }
 
     /// Returns the `Analysis` used to generate the underlying `Results`.
     pub fn mut_analysis(&mut self) -> &mut A {
-        &mut self.results.borrow_mut().analysis
+        &mut self.results.analysis
     }
 
     /// Resets the cursor to hold the entry set for the given basic block.
@@ -175,7 +109,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.entry_set_for_block(block));
         self.pos = CursorPosition::block_entry(block);
         self.state_needs_reset = false;
     }
@@ -264,11 +198,10 @@ where
             )
         };
 
-        let analysis = &mut self.results.borrow_mut().analysis;
         let target_effect_index = effect.at_index(target.statement_index);
 
         A::Direction::apply_effects_in_range(
-            analysis,
+            &mut self.results.analysis,
             &mut self.state,
             target.block,
             block_data,
@@ -284,12 +217,12 @@ 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.results.borrow_mut().analysis, &mut self.state);
+        f(&mut self.results.analysis, &mut self.state);
         self.state_needs_reset = true;
     }
 }
 
-impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
+impl<'mir, 'tcx, A> ResultsCursor<'mir, 'tcx, A>
 where
     A: crate::GenKillAnalysis<'tcx>,
     A::Domain: BitSetExt<A::Idx>,
diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs
index ed82b1e8cdc..784872c7ed7 100644
--- a/compiler/rustc_mir_dataflow/src/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs
@@ -5,9 +5,7 @@ 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;
@@ -24,42 +22,37 @@ use rustc_span::symbol::{sym, Symbol};
 use super::fmt::DebugWithContext;
 use super::graphviz;
 use super::{
-    visit_results, Analysis, AnalysisDomain, CloneAnalysis, Direction, GenKill, GenKillAnalysis,
-    GenKillSet, JoinSemiLattice, ResultsClonedCursor, ResultsCursor, ResultsRefCursor,
-    ResultsVisitor,
+    visit_results, Analysis, AnalysisDomain, Direction, GenKill, GenKillAnalysis, GenKillSet,
+    JoinSemiLattice, ResultsCursor, 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, E = EntrySets<'tcx, A>>
+#[derive(Clone)]
+pub struct Results<'tcx, A>
 where
     A: Analysis<'tcx>,
 {
     pub analysis: A,
-    pub(super) entry_sets: E,
-    pub(super) _marker: PhantomData<&'tcx ()>,
+    pub(super) entry_sets: EntrySets<'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>
+impl<'tcx, A> Results<'tcx, A>
 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, Self> {
+    ) -> ResultsCursor<'mir, 'tcx, A> {
         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.borrow()[block]
+        &self.entry_sets[block]
     }
 
     pub fn visit_with<'mir>(
@@ -80,52 +73,6 @@ where
         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<'mir, 'tcx, A>
@@ -291,29 +238,31 @@ where
             );
         }
 
-        let mut results = Results { analysis, entry_sets, _marker: PhantomData };
+        let results = Results { analysis, entry_sets };
 
         if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
-            let res = write_graphviz_results(tcx, body, &mut results, pass_name);
+            let (res, results) = write_graphviz_results(tcx, body, results, pass_name);
             if let Err(e) = res {
                 error!("Failed to write graphviz dataflow results: {}", e);
             }
+            results
+        } else {
+            results
         }
-
-        results
     }
 }
 
 // Graphviz
 
 /// Writes a DOT file containing the results of a dataflow analysis if the user requested it via
-/// `rustc_mir` attributes and `-Z dump-mir-dataflow`.
+/// `rustc_mir` attributes and `-Z dump-mir-dataflow`. The `Result` in and the `Results` out are
+/// the same.
 fn write_graphviz_results<'tcx, A>(
     tcx: TyCtxt<'tcx>,
     body: &mir::Body<'tcx>,
-    results: &mut Results<'tcx, A>,
+    results: Results<'tcx, A>,
     pass_name: Option<&'static str>,
-) -> std::io::Result<()>
+) -> (std::io::Result<()>, Results<'tcx, A>)
 where
     A: Analysis<'tcx>,
     A::Domain: DebugWithContext<A>,
@@ -324,23 +273,30 @@ where
     let def_id = body.source.def_id();
     let Ok(attrs) = RustcMirAttrs::parse(tcx, def_id) else {
         // Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse`
-        return Ok(());
+        return (Ok(()), results);
     };
 
-    let mut file = match attrs.output_path(A::NAME) {
-        Some(path) => {
-            debug!("printing dataflow results for {:?} to {}", def_id, path.display());
-            if let Some(parent) = path.parent() {
-                fs::create_dir_all(parent)?;
+    let file = try {
+        match attrs.output_path(A::NAME) {
+            Some(path) => {
+                debug!("printing dataflow results for {:?} to {}", def_id, path.display());
+                if let Some(parent) = path.parent() {
+                    fs::create_dir_all(parent)?;
+                }
+                let f = fs::File::create(&path)?;
+                io::BufWriter::new(f)
             }
-            io::BufWriter::new(fs::File::create(&path)?)
-        }
 
-        None if dump_enabled(tcx, A::NAME, def_id) => {
-            create_dump_file(tcx, ".dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)?
-        }
+            None if dump_enabled(tcx, A::NAME, def_id) => {
+                create_dump_file(tcx, ".dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)?
+            }
 
-        _ => return Ok(()),
+            _ => return (Ok(()), results),
+        }
+    };
+    let mut file = match file {
+        Ok(f) => f,
+        Err(e) => return (Err(e), results),
     };
 
     let style = match attrs.formatter {
@@ -356,11 +312,14 @@ where
     if tcx.sess.opts.unstable_opts.graphviz_dark_mode {
         render_opts.push(dot::RenderOption::DarkTheme);
     }
-    with_no_trimmed_paths!(dot::render_opts(&graphviz, &mut buf, &render_opts)?);
+    let r = with_no_trimmed_paths!(dot::render_opts(&graphviz, &mut buf, &render_opts));
 
-    file.write_all(&buf)?;
+    let lhs = try {
+        r?;
+        file.write_all(&buf)?;
+    };
 
-    Ok(())
+    (lhs, graphviz.into_results())
 }
 
 #[derive(Default)]
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index 832d1cba9a7..fa16cac3168 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -12,7 +12,7 @@ use rustc_middle::mir::graphviz_safe_def_name;
 use rustc_middle::mir::{self, BasicBlock, Body, Location};
 
 use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext};
-use super::{Analysis, CallReturnPlaces, Direction, Results, ResultsRefCursor, ResultsVisitor};
+use super::{Analysis, CallReturnPlaces, Direction, Results, ResultsCursor, ResultsVisitor};
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub(crate) enum OutputStyle {
@@ -29,27 +29,31 @@ impl OutputStyle {
     }
 }
 
-pub(crate) struct Formatter<'res, 'mir, 'tcx, A>
+pub(crate) struct Formatter<'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
     body: &'mir Body<'tcx>,
-    results: RefCell<&'res mut Results<'tcx, A>>,
+    results: RefCell<Option<Results<'tcx, A>>>,
     style: OutputStyle,
     reachable: BitSet<BasicBlock>,
 }
 
-impl<'res, 'mir, 'tcx, A> Formatter<'res, 'mir, 'tcx, A>
+impl<'mir, 'tcx, A> Formatter<'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
     pub(crate) fn new(
         body: &'mir Body<'tcx>,
-        results: &'res mut Results<'tcx, A>,
+        results: Results<'tcx, A>,
         style: OutputStyle,
     ) -> Self {
         let reachable = mir::traversal::reachable_as_bitset(body);
-        Formatter { body, results: results.into(), style, reachable }
+        Formatter { body, results: Some(results).into(), style, reachable }
+    }
+
+    pub(crate) fn into_results(self) -> Results<'tcx, A> {
+        self.results.into_inner().unwrap()
     }
 }
 
@@ -69,7 +73,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>,
@@ -88,14 +92,19 @@ 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: results.as_results_cursor(self.body),
-            style: self.style,
-            bg: Background::Light,
-        };
+        self.results.replace_with(|results| {
+            // `Formatter::result` is a `RefCell<Option<_>>` so we can replace
+            // the value with `None`, move it into the results cursor, move it
+            // back out, and return it to the refcell wrapped in `Some`.
+            let mut fmt = BlockFormatter {
+                results: results.take().unwrap().into_results_cursor(self.body),
+                style: self.style,
+                bg: Background::Light,
+            };
 
-        fmt.write_node_label(&mut label, *block).unwrap();
+            fmt.write_node_label(&mut label, *block).unwrap();
+            Some(fmt.results.into_results())
+        });
         dot::LabelText::html(String::from_utf8(label).unwrap())
     }
 
@@ -109,7 +118,7 @@ where
     }
 }
 
-impl<'mir, 'tcx, A> dot::GraphWalk<'mir> for Formatter<'_, 'mir, 'tcx, A>
+impl<'mir, 'tcx, A> dot::GraphWalk<'mir> for Formatter<'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
@@ -143,16 +152,16 @@ where
     }
 }
 
-struct BlockFormatter<'res, 'mir, 'tcx, A>
+struct BlockFormatter<'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
-    results: ResultsRefCursor<'res, 'mir, 'tcx, A>,
+    results: ResultsCursor<'mir, 'tcx, A>,
     bg: Background,
     style: OutputStyle,
 }
 
-impl<'res, 'mir, 'tcx, A> BlockFormatter<'res, 'mir, 'tcx, A>
+impl<'mir, 'tcx, A> BlockFormatter<'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
     A::Domain: DebugWithContext<A>,
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index a5ae1edf221..b7dfbe0710d 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::{ResultsClonedCursor, ResultsCursor, ResultsRefCursor};
+pub use self::cursor::ResultsCursor;
 pub use self::direction::{Backward, Direction, Forward};
-pub use self::engine::{Engine, EntrySets, Results, ResultsCloned};
+pub use self::engine::{Engine, Results};
 pub use self::lattice::{JoinSemiLattice, MaybeReachable};
 pub use self::visitor::{visit_results, ResultsVisitable, ResultsVisitor};
 
@@ -246,21 +246,6 @@ 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
diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs
index 9cce5b26cd3..1da5057ff40 100644
--- a/compiler/rustc_mir_dataflow/src/framework/tests.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs
@@ -267,8 +267,7 @@ fn test_cursor<D: Direction>(analysis: MockAnalysis<'_, D>) {
     let body = analysis.body;
 
     let mut cursor =
-        Results { entry_sets: analysis.mock_entry_sets(), analysis, _marker: PhantomData }
-            .into_results_cursor(body);
+        Results { entry_sets: analysis.mock_entry_sets(), 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 3cfa7cc1c02..e3648bb4076 100644
--- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
@@ -1,8 +1,6 @@
-use std::borrow::Borrow;
-
 use rustc_middle::mir::{self, BasicBlock, Location};
 
-use super::{Analysis, Direction, EntrySets, Results};
+use super::{Analysis, Direction, Results};
 
 /// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the
 /// dataflow state at that location.
@@ -143,10 +141,9 @@ pub trait ResultsVisitable<'tcx> {
     );
 }
 
-impl<'tcx, A, E> ResultsVisitable<'tcx> for Results<'tcx, A, E>
+impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A>
 where
     A: Analysis<'tcx>,
-    E: Borrow<EntrySets<'tcx, A>>,
 {
     type FlowState = A::Domain;
 
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index 5a58e3af8be..26fc903973f 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -5,7 +5,7 @@ use rustc_middle::mir::*;
 use std::borrow::Cow;
 
 use super::MaybeBorrowedLocals;
-use crate::{GenKill, ResultsClonedCursor};
+use crate::{GenKill, ResultsCursor};
 
 #[derive(Clone)]
 pub struct MaybeStorageLive<'a> {
@@ -18,12 +18,6 @@ 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>;
 
@@ -158,28 +152,21 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead {
     }
 }
 
-type BorrowedLocalsResults<'res, 'mir, 'tcx> =
-    ResultsClonedCursor<'res, 'mir, 'tcx, MaybeBorrowedLocals>;
+type BorrowedLocalsResults<'mir, 'tcx> = ResultsCursor<'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<'res, 'mir, 'tcx> {
-    borrowed_locals: BorrowedLocalsResults<'res, 'mir, 'tcx>,
+pub struct MaybeRequiresStorage<'mir, 'tcx> {
+    borrowed_locals: BorrowedLocalsResults<'mir, 'tcx>,
 }
 
-impl<'res, 'mir, 'tcx> MaybeRequiresStorage<'res, 'mir, 'tcx> {
-    pub fn new(borrowed_locals: BorrowedLocalsResults<'res, 'mir, 'tcx>) -> Self {
+impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
+    pub fn new(borrowed_locals: BorrowedLocalsResults<'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<'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> {
+impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
     type Domain = BitSet<Local>;
 
     const NAME: &'static str = "requires_storage";
@@ -198,7 +185,7 @@ impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> {
     }
 }
 
-impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> {
+impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> {
     type Idx = Local;
 
     fn domain_size(&self, body: &Body<'tcx>) -> usize {
@@ -355,7 +342,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> {
     }
 }
 
-impl<'tcx> MaybeRequiresStorage<'_, '_, 'tcx> {
+impl<'tcx> MaybeRequiresStorage<'_, 'tcx> {
     /// Kill locals that are fully moved and have not been borrowed.
     fn check_for_move(&mut self, trans: &mut impl GenKill<Local>, loc: Location) {
         let body = self.borrowed_locals.body();
@@ -364,12 +351,12 @@ impl<'tcx> MaybeRequiresStorage<'_, '_, 'tcx> {
     }
 }
 
-struct MoveVisitor<'a, 'res, 'mir, 'tcx, T> {
-    borrowed_locals: &'a mut BorrowedLocalsResults<'res, 'mir, 'tcx>,
+struct MoveVisitor<'a, 'mir, 'tcx, T> {
+    borrowed_locals: &'a mut BorrowedLocalsResults<'mir, 'tcx>,
     trans: &'a mut T,
 }
 
-impl<'tcx, T> Visitor<'tcx> for MoveVisitor<'_, '_, '_, 'tcx, T>
+impl<'tcx, T> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx, T>
 where
     T: GenKill<Local>,
 {
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index d218f033d62..f0b21fd4184 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -4,6 +4,7 @@
 #![feature(let_chains)]
 #![feature(min_specialization)]
 #![feature(stmt_expr_attributes)]
+#![feature(try_blocks)]
 #![recursion_limit = "256"]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
@@ -23,7 +24,7 @@ pub use self::framework::{
     fmt, lattice, visit_results, Analysis, AnalysisDomain, Direction, GenKill, GenKillAnalysis,
     JoinSemiLattice, MaybeReachable, Results, ResultsCursor, ResultsVisitable, ResultsVisitor,
 };
-use self::framework::{Backward, CloneAnalysis, ResultsClonedCursor, SwitchIntEdgeEffects};
+use self::framework::{Backward, SwitchIntEdgeEffects};
 use self::move_paths::MoveData;
 
 pub mod debuginfo;
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 1373596fd2b..79a1509531d 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -679,15 +679,15 @@ fn locals_live_across_suspend_points<'tcx>(
     let borrowed_locals_results =
         MaybeBorrowedLocals.into_engine(tcx, body).pass_name("coroutine").iterate_to_fixpoint();
 
-    let mut borrowed_locals_cursor = borrowed_locals_results.cloned_results_cursor(body);
+    let mut borrowed_locals_cursor = borrowed_locals_results.clone().into_results_cursor(body);
 
     // Calculate the MIR locals that we actually need to keep storage around
     // for.
-    let mut requires_storage_results =
-        MaybeRequiresStorage::new(borrowed_locals_results.cloned_results_cursor(body))
+    let mut requires_storage_cursor =
+        MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body))
             .into_engine(tcx, body)
-            .iterate_to_fixpoint();
-    let mut requires_storage_cursor = requires_storage_results.as_results_cursor(body);
+            .iterate_to_fixpoint()
+            .into_results_cursor(body);
 
     // Calculate the liveness of MIR locals ignoring borrows.
     let mut liveness = MaybeLiveLocals
@@ -763,7 +763,7 @@ fn locals_live_across_suspend_points<'tcx>(
         body,
         &saved_locals,
         always_live_locals.clone(),
-        requires_storage_results,
+        requires_storage_cursor.into_results(),
     );
 
     LivenessInfo {
@@ -828,7 +828,7 @@ fn compute_storage_conflicts<'mir, 'tcx>(
     body: &'mir Body<'tcx>,
     saved_locals: &CoroutineSavedLocals,
     always_live_locals: BitSet<Local>,
-    mut requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'_, 'mir, 'tcx>>,
+    mut requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
 ) -> BitMatrix<CoroutineSavedLocal, CoroutineSavedLocal> {
     assert_eq!(body.local_decls.len(), saved_locals.domain_size());