about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan MacKenzie <ecstaticmorse@gmail.com>2020-08-28 13:26:25 -0700
committerDylan MacKenzie <ecstaticmorse@gmail.com>2020-08-30 11:15:25 -0700
commitb19b8ea6113a6e912d508c11a25567b05d7db54c (patch)
treebf06392d97321685f0a742054ffbbc94090452ec
parent3233fb18a891363a2da36ce69ca16fbb219c96be (diff)
downloadrust-b19b8ea6113a6e912d508c11a25567b05d7db54c.tar.gz
rust-b19b8ea6113a6e912d508c11a25567b05d7db54c.zip
Update dataflow analyses to use new interface
-rw-r--r--compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs17
-rw-r--r--compiler/rustc_mir/src/dataflow/impls/borrows.rs26
-rw-r--r--compiler/rustc_mir/src/dataflow/impls/init_locals.rs18
-rw-r--r--compiler/rustc_mir/src/dataflow/impls/liveness.rs18
-rw-r--r--compiler/rustc_mir/src/dataflow/impls/mod.rs85
-rw-r--r--compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs33
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/resolver.rs18
-rw-r--r--compiler/rustc_mir/src/transform/rustc_peek.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs17
9 files changed, 106 insertions, 143 deletions
diff --git a/compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs b/compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs
index a3fc51cad65..65e04ed6831 100644
--- a/compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs
@@ -82,15 +82,15 @@ impl<K> AnalysisDomain<'tcx> for MaybeBorrowedLocals<K>
 where
     K: BorrowAnalysisKind<'tcx>,
 {
-    type Idx = Local;
-
+    type Domain = BitSet<Local>;
     const NAME: &'static str = K::ANALYSIS_NAME;
 
-    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
-        body.local_decls().len()
+    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
+        // bottom = unborrowed
+        BitSet::new_empty(body.local_decls().len())
     }
 
-    fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut BitSet<Self::Idx>) {
+    fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
         // No locals are aliased on function entry
     }
 }
@@ -99,6 +99,8 @@ impl<K> GenKillAnalysis<'tcx> for MaybeBorrowedLocals<K>
 where
     K: BorrowAnalysisKind<'tcx>,
 {
+    type Idx = Local;
+
     fn statement_effect(
         &self,
         trans: &mut impl GenKill<Self::Idx>,
@@ -128,11 +130,6 @@ where
     }
 }
 
-impl<K> BottomValue for MaybeBorrowedLocals<K> {
-    // bottom = unborrowed
-    const BOTTOM_VALUE: bool = false;
-}
-
 /// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`.
 struct TransferFunction<'a, T, K> {
     trans: &'a mut T,
diff --git a/compiler/rustc_mir/src/dataflow/impls/borrows.rs b/compiler/rustc_mir/src/dataflow/impls/borrows.rs
index aeb7ffe3e3b..0be13b6ba81 100644
--- a/compiler/rustc_mir/src/dataflow/impls/borrows.rs
+++ b/compiler/rustc_mir/src/dataflow/impls/borrows.rs
@@ -8,9 +8,9 @@ use rustc_index::bit_set::BitSet;
 use crate::borrow_check::{
     places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid,
 };
-use crate::dataflow::BottomValue;
-use crate::dataflow::{self, GenKill};
+use crate::dataflow::{self, fmt::DebugWithContext, GenKill};
 
+use std::fmt;
 use std::rc::Rc;
 
 rustc_index::newtype_index! {
@@ -227,25 +227,24 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
 }
 
 impl<'tcx> dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> {
-    type Idx = BorrowIndex;
+    type Domain = BitSet<BorrowIndex>;
 
     const NAME: &'static str = "borrows";
 
-    fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize {
-        self.borrow_set.len() * 2
+    fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
+        // bottom = nothing is reserved or activated yet;
+        BitSet::new_empty(self.borrow_set.len() * 2)
     }
 
-    fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut BitSet<Self::Idx>) {
+    fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
         // no borrows of code region_scopes have been taken prior to
         // function execution, so this method has no effect.
     }
-
-    fn pretty_print_idx(&self, w: &mut impl std::io::Write, idx: Self::Idx) -> std::io::Result<()> {
-        write!(w, "{:?}", self.location(idx))
-    }
 }
 
 impl<'tcx> dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
+    type Idx = BorrowIndex;
+
     fn before_statement_effect(
         &self,
         trans: &mut impl GenKill<Self::Idx>,
@@ -344,7 +343,8 @@ impl<'tcx> dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> BottomValue for Borrows<'a, 'tcx> {
-    /// bottom = nothing is reserved or activated yet;
-    const BOTTOM_VALUE: bool = false;
+impl DebugWithContext<Borrows<'_, '_>> for BorrowIndex {
+    fn fmt_with(&self, ctxt: &Borrows<'_, '_>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:?}", ctxt.location(*self))
+    }
 }
diff --git a/compiler/rustc_mir/src/dataflow/impls/init_locals.rs b/compiler/rustc_mir/src/dataflow/impls/init_locals.rs
index 0e7cd1bb0e4..5da302cd1fd 100644
--- a/compiler/rustc_mir/src/dataflow/impls/init_locals.rs
+++ b/compiler/rustc_mir/src/dataflow/impls/init_locals.rs
@@ -2,7 +2,7 @@
 //!
 //! A local will be maybe initialized if *any* projections of that local might be initialized.
 
-use crate::dataflow::{self, BottomValue, GenKill};
+use crate::dataflow::{self, GenKill};
 
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
@@ -10,21 +10,17 @@ use rustc_middle::mir::{self, BasicBlock, Local, Location};
 
 pub struct MaybeInitializedLocals;
 
-impl BottomValue for MaybeInitializedLocals {
-    /// bottom = uninit
-    const BOTTOM_VALUE: bool = false;
-}
-
 impl dataflow::AnalysisDomain<'tcx> for MaybeInitializedLocals {
-    type Idx = Local;
+    type Domain = BitSet<Local>;
 
     const NAME: &'static str = "maybe_init_locals";
 
-    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
-        body.local_decls.len()
+    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
+        // bottom = uninit
+        BitSet::new_empty(body.local_decls.len())
     }
 
-    fn initialize_start_block(&self, body: &mir::Body<'tcx>, entry_set: &mut BitSet<Self::Idx>) {
+    fn initialize_start_block(&self, body: &mir::Body<'tcx>, entry_set: &mut Self::Domain) {
         // Function arguments are initialized to begin with.
         for arg in body.args_iter() {
             entry_set.insert(arg);
@@ -33,6 +29,8 @@ impl dataflow::AnalysisDomain<'tcx> for MaybeInitializedLocals {
 }
 
 impl dataflow::GenKillAnalysis<'tcx> for MaybeInitializedLocals {
+    type Idx = Local;
+
     fn statement_effect(
         &self,
         trans: &mut impl GenKill<Self::Idx>,
diff --git a/compiler/rustc_mir/src/dataflow/impls/liveness.rs b/compiler/rustc_mir/src/dataflow/impls/liveness.rs
index 784b0bd9293..b0da28156d1 100644
--- a/compiler/rustc_mir/src/dataflow/impls/liveness.rs
+++ b/compiler/rustc_mir/src/dataflow/impls/liveness.rs
@@ -2,7 +2,7 @@ use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::{self, Local, Location};
 
-use crate::dataflow::{AnalysisDomain, Backward, BottomValue, GenKill, GenKillAnalysis};
+use crate::dataflow::{AnalysisDomain, Backward, GenKill, GenKillAnalysis};
 
 /// A [live-variable dataflow analysis][liveness].
 ///
@@ -22,27 +22,25 @@ impl MaybeLiveLocals {
     }
 }
 
-impl BottomValue for MaybeLiveLocals {
-    // bottom = not live
-    const BOTTOM_VALUE: bool = false;
-}
-
 impl AnalysisDomain<'tcx> for MaybeLiveLocals {
-    type Idx = Local;
+    type Domain = BitSet<Local>;
     type Direction = Backward;
 
     const NAME: &'static str = "liveness";
 
-    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
-        body.local_decls.len()
+    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
+        // bottom = not live
+        BitSet::new_empty(body.local_decls.len())
     }
 
-    fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut BitSet<Self::Idx>) {
+    fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
         // No variables are live until we observe a use
     }
 }
 
 impl GenKillAnalysis<'tcx> for MaybeLiveLocals {
+    type Idx = Local;
+
     fn statement_effect(
         &self,
         trans: &mut impl GenKill<Self::Idx>,
diff --git a/compiler/rustc_mir/src/dataflow/impls/mod.rs b/compiler/rustc_mir/src/dataflow/impls/mod.rs
index 8975faec487..c42d5867856 100644
--- a/compiler/rustc_mir/src/dataflow/impls/mod.rs
+++ b/compiler/rustc_mir/src/dataflow/impls/mod.rs
@@ -13,7 +13,7 @@ use super::MoveDataParamEnv;
 use crate::util::elaborate_drops::DropFlagState;
 
 use super::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex};
-use super::{AnalysisDomain, BottomValue, GenKill, GenKillAnalysis};
+use super::{lattice, AnalysisDomain, GenKill, GenKillAnalysis};
 
 use super::drop_flag_effects_for_function_entry;
 use super::drop_flag_effects_for_location;
@@ -290,27 +290,25 @@ impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
 }
 
 impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
-    type Idx = MovePathIndex;
-
+    type Domain = BitSet<MovePathIndex>;
     const NAME: &'static str = "maybe_init";
 
-    fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize {
-        self.move_data().move_paths.len()
+    fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
+        // bottom = uninitialized
+        BitSet::new_empty(self.move_data().move_paths.len())
     }
 
-    fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
+    fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
         drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| {
             assert!(s == DropFlagState::Present);
             state.insert(path);
         });
     }
-
-    fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> {
-        write!(w, "{}", self.move_data().move_paths[mpi])
-    }
 }
 
 impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
+    type Idx = MovePathIndex;
+
     fn statement_effect(
         &self,
         trans: &mut impl GenKill<Self::Idx>,
@@ -376,18 +374,18 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
 }
 
 impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
-    type Idx = MovePathIndex;
+    type Domain = BitSet<MovePathIndex>;
 
     const NAME: &'static str = "maybe_uninit";
 
-    fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize {
-        self.move_data().move_paths.len()
+    fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
+        // bottom = initialized (start_block_effect counters this at outset)
+        BitSet::new_empty(self.move_data().move_paths.len())
     }
 
     // sets on_entry bits for Arg places
-    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
+    fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
         // set all bits to 1 (uninit) before gathering counterevidence
-        assert!(self.bits_per_block(body) == state.domain_size());
         state.insert_all();
 
         drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| {
@@ -395,13 +393,11 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
             state.remove(path);
         });
     }
-
-    fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> {
-        write!(w, "{}", self.move_data().move_paths[mpi])
-    }
 }
 
 impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
+    type Idx = MovePathIndex;
+
     fn statement_effect(
         &self,
         trans: &mut impl GenKill<Self::Idx>,
@@ -471,30 +467,30 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
 }
 
 impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
-    type Idx = MovePathIndex;
+    /// Use set intersection as the join operator.
+    type Domain = lattice::Dual<BitSet<MovePathIndex>>;
 
     const NAME: &'static str = "definite_init";
 
-    fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize {
-        self.move_data().move_paths.len()
+    fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
+        // bottom = initialized (start_block_effect counters this at outset)
+        lattice::Dual(BitSet::new_filled(self.move_data().move_paths.len()))
     }
 
     // sets on_entry bits for Arg places
-    fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
-        state.clear();
+    fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
+        state.0.clear();
 
         drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| {
             assert!(s == DropFlagState::Present);
-            state.insert(path);
+            state.0.insert(path);
         });
     }
-
-    fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> {
-        write!(w, "{}", self.move_data().move_paths[mpi])
-    }
 }
 
 impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
+    type Idx = MovePathIndex;
+
     fn statement_effect(
         &self,
         trans: &mut impl GenKill<Self::Idx>,
@@ -540,15 +536,16 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
 }
 
 impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> {
-    type Idx = InitIndex;
+    type Domain = BitSet<InitIndex>;
 
     const NAME: &'static str = "ever_init";
 
-    fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize {
-        self.move_data().inits.len()
+    fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
+        // bottom = no initialized variables by default
+        BitSet::new_empty(self.move_data().inits.len())
     }
 
-    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
+    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
         for arg_init in 0..body.arg_count {
             state.insert(InitIndex::new(arg_init));
         }
@@ -556,6 +553,8 @@ impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> {
 }
 
 impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
+    type Idx = InitIndex;
+
     fn statement_effect(
         &self,
         trans: &mut impl GenKill<Self::Idx>,
@@ -625,23 +624,3 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
         }
     }
 }
-
-impl<'a, 'tcx> BottomValue for MaybeInitializedPlaces<'a, 'tcx> {
-    /// bottom = uninitialized
-    const BOTTOM_VALUE: bool = false;
-}
-
-impl<'a, 'tcx> BottomValue for MaybeUninitializedPlaces<'a, 'tcx> {
-    /// bottom = initialized (start_block_effect counters this at outset)
-    const BOTTOM_VALUE: bool = false;
-}
-
-impl<'a, 'tcx> BottomValue for DefinitelyInitializedPlaces<'a, 'tcx> {
-    /// bottom = initialized (start_block_effect counters this at outset)
-    const BOTTOM_VALUE: bool = true;
-}
-
-impl<'a, 'tcx> BottomValue for EverInitializedPlaces<'a, 'tcx> {
-    /// bottom = no initialized variables by default
-    const BOTTOM_VALUE: bool = false;
-}
diff --git a/compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs b/compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs
index 21623e3cad5..9250cd40847 100644
--- a/compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs
+++ b/compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs
@@ -1,6 +1,5 @@
 pub use super::*;
 
-use crate::dataflow::BottomValue;
 use crate::dataflow::{self, GenKill, Results, ResultsRefCursor};
 use crate::util::storage::AlwaysLiveLocals;
 use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
@@ -19,15 +18,16 @@ impl MaybeStorageLive {
 }
 
 impl dataflow::AnalysisDomain<'tcx> for MaybeStorageLive {
-    type Idx = Local;
+    type Domain = BitSet<Local>;
 
     const NAME: &'static str = "maybe_storage_live";
 
-    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
-        body.local_decls.len()
+    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
+        // bottom = dead
+        BitSet::new_empty(body.local_decls.len())
     }
 
-    fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut BitSet<Self::Idx>) {
+    fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut Self::Domain) {
         assert_eq!(body.local_decls.len(), self.always_live_locals.domain_size());
         for local in self.always_live_locals.iter() {
             on_entry.insert(local);
@@ -40,6 +40,8 @@ impl dataflow::AnalysisDomain<'tcx> for MaybeStorageLive {
 }
 
 impl dataflow::GenKillAnalysis<'tcx> for MaybeStorageLive {
+    type Idx = Local;
+
     fn statement_effect(
         &self,
         trans: &mut impl GenKill<Self::Idx>,
@@ -74,11 +76,6 @@ impl dataflow::GenKillAnalysis<'tcx> for MaybeStorageLive {
     }
 }
 
-impl BottomValue for MaybeStorageLive {
-    /// bottom = dead
-    const BOTTOM_VALUE: bool = false;
-}
-
 type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>;
 
 /// Dataflow analysis that determines whether each local requires storage at a
@@ -101,15 +98,16 @@ impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
 }
 
 impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
-    type Idx = Local;
+    type Domain = BitSet<Local>;
 
     const NAME: &'static str = "requires_storage";
 
-    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
-        body.local_decls.len()
+    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
+        // bottom = dead
+        BitSet::new_empty(body.local_decls.len())
     }
 
-    fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut BitSet<Self::Idx>) {
+    fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut Self::Domain) {
         // The resume argument is live on function entry (we don't care about
         // the `self` argument)
         for arg in body.args_iter().skip(1) {
@@ -119,6 +117,8 @@ impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, '
 }
 
 impl<'mir, 'tcx> dataflow::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
+    type Idx = Local;
+
     fn before_statement_effect(
         &self,
         trans: &mut impl GenKill<Self::Idx>,
@@ -285,11 +285,6 @@ impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
     }
 }
 
-impl<'mir, 'tcx> BottomValue for MaybeRequiresStorage<'mir, 'tcx> {
-    /// bottom = dead
-    const BOTTOM_VALUE: bool = false;
-}
-
 struct MoveVisitor<'a, 'mir, 'tcx, T> {
     borrowed_locals: &'a RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
     trans: &'a mut T,
diff --git a/compiler/rustc_mir/src/transform/check_consts/resolver.rs b/compiler/rustc_mir/src/transform/check_consts/resolver.rs
index b8104292aab..a00301952b3 100644
--- a/compiler/rustc_mir/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/resolver.rs
@@ -165,23 +165,19 @@ where
     }
 }
 
-impl<Q> dataflow::BottomValue for FlowSensitiveAnalysis<'_, '_, '_, Q> {
-    const BOTTOM_VALUE: bool = false;
-}
-
 impl<Q> dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
 where
     Q: Qualif,
 {
-    type Idx = Local;
+    type Domain = BitSet<Local>;
 
     const NAME: &'static str = Q::ANALYSIS_NAME;
 
-    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
-        body.local_decls.len()
+    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
+        BitSet::new_empty(body.local_decls.len())
     }
 
-    fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
+    fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut Self::Domain) {
         self.transfer_function(state).initialize_state();
     }
 }
@@ -192,7 +188,7 @@ where
 {
     fn apply_statement_effect(
         &self,
-        state: &mut BitSet<Self::Idx>,
+        state: &mut Self::Domain,
         statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
@@ -201,7 +197,7 @@ where
 
     fn apply_terminator_effect(
         &self,
-        state: &mut BitSet<Self::Idx>,
+        state: &mut Self::Domain,
         terminator: &mir::Terminator<'tcx>,
         location: Location,
     ) {
@@ -210,7 +206,7 @@ where
 
     fn apply_call_return_effect(
         &self,
-        state: &mut BitSet<Self::Idx>,
+        state: &mut Self::Domain,
         block: BasicBlock,
         func: &mir::Operand<'tcx>,
         args: &[mir::Operand<'tcx>],
diff --git a/compiler/rustc_mir/src/transform/rustc_peek.rs b/compiler/rustc_mir/src/transform/rustc_peek.rs
index 00d269a4af8..07ce3100d89 100644
--- a/compiler/rustc_mir/src/transform/rustc_peek.rs
+++ b/compiler/rustc_mir/src/transform/rustc_peek.rs
@@ -1,4 +1,6 @@
-use rustc_ast as ast;
+use std::borrow::Borrow;
+
+use rustc_ast::ast;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
@@ -16,7 +18,7 @@ use crate::dataflow::impls::{
 use crate::dataflow::move_paths::{HasMoveData, MoveData};
 use crate::dataflow::move_paths::{LookupResult, MovePathIndex};
 use crate::dataflow::MoveDataParamEnv;
-use crate::dataflow::{Analysis, Results, ResultsCursor};
+use crate::dataflow::{Analysis, JoinSemiLattice, Results, ResultsCursor};
 
 pub struct SanityCheck;
 
@@ -248,25 +250,26 @@ pub trait RustcPeekAt<'tcx>: Analysis<'tcx> {
         &self,
         tcx: TyCtxt<'tcx>,
         place: mir::Place<'tcx>,
-        flow_state: &BitSet<Self::Idx>,
+        flow_state: &Self::Domain,
         call: PeekCall,
     );
 }
 
-impl<'tcx, A> RustcPeekAt<'tcx> for A
+impl<'tcx, A, D> RustcPeekAt<'tcx> for A
 where
-    A: Analysis<'tcx, Idx = MovePathIndex> + HasMoveData<'tcx>,
+    A: Analysis<'tcx, Domain = D> + HasMoveData<'tcx>,
+    D: JoinSemiLattice + Clone + Borrow<BitSet<MovePathIndex>>,
 {
     fn peek_at(
         &self,
         tcx: TyCtxt<'tcx>,
         place: mir::Place<'tcx>,
-        flow_state: &BitSet<Self::Idx>,
+        flow_state: &Self::Domain,
         call: PeekCall,
     ) {
         match self.move_data().rev_lookup.find(place.as_ref()) {
             LookupResult::Exact(peek_mpi) => {
-                let bit_state = flow_state.contains(peek_mpi);
+                let bit_state = flow_state.borrow().contains(peek_mpi);
                 debug!("rustc_peek({:?} = &{:?}) bit_state: {}", call.arg, place, bit_state);
                 if !bit_state {
                     tcx.sess.span_err(call.span, "rustc_peek: bit not set");
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index 7932be0d4b1..aec99cb4063 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -14,7 +14,6 @@ use rustc_middle::mir::{
     visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _},
 };
 use rustc_middle::ty::{self, fold::TypeVisitor, Ty};
-use rustc_mir::dataflow::BottomValue;
 use rustc_mir::dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::{BytePos, Span};
@@ -411,14 +410,15 @@ impl<'tcx> mir::visit::Visitor<'tcx> for LocalUseVisitor {
 struct MaybeStorageLive;
 
 impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive {
-    type Idx = mir::Local;
+    type Domain = BitSet<mir::Local>;
     const NAME: &'static str = "maybe_storage_live";
 
-    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
-        body.local_decls.len()
+    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
+        // bottom = dead
+        BitSet::new_empty(body.local_decls.len())
     }
 
-    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>) {
+    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
         for arg in body.args_iter() {
             state.insert(arg);
         }
@@ -426,6 +426,8 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive {
 }
 
 impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
+    type Idx = mir::Local;
+
     fn statement_effect(&self, trans: &mut impl GenKill<Self::Idx>, stmt: &mir::Statement<'tcx>, _: mir::Location) {
         match stmt.kind {
             mir::StatementKind::StorageLive(l) => trans.gen(l),
@@ -454,11 +456,6 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
     }
 }
 
-impl BottomValue for MaybeStorageLive {
-    /// bottom = dead
-    const BOTTOM_VALUE: bool = false;
-}
-
 /// Collects the possible borrowers of each local.
 /// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
 /// possible borrowers of `a`.