about summary refs log tree commit diff
path: root/compiler/rustc_mir/src/dataflow/impls
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2021-01-05 19:53:07 +0100
committerCamille GILLOT <gillot.camille@gmail.com>2021-09-07 19:57:07 +0200
commitfd9c04fe32d3b7700d600ae1be72d5758ffd66ff (patch)
tree9968ed2ae3ef44610f7669a5221d9a502f33765f /compiler/rustc_mir/src/dataflow/impls
parent81a600b6b7db07ebac28c8ddedd357e3c5b9951d (diff)
downloadrust-fd9c04fe32d3b7700d600ae1be72d5758ffd66ff.tar.gz
rust-fd9c04fe32d3b7700d600ae1be72d5758ffd66ff.zip
Move the dataflow framework to its own crate.
Diffstat (limited to 'compiler/rustc_mir/src/dataflow/impls')
-rw-r--r--compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs273
-rw-r--r--compiler/rustc_mir/src/dataflow/impls/init_locals.rs113
-rw-r--r--compiler/rustc_mir/src/dataflow/impls/liveness.rs165
-rw-r--r--compiler/rustc_mir/src/dataflow/impls/mod.rs715
-rw-r--r--compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs307
5 files changed, 0 insertions, 1573 deletions
diff --git a/compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs b/compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs
deleted file mode 100644
index 65e04ed6831..00000000000
--- a/compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs
+++ /dev/null
@@ -1,273 +0,0 @@
-pub use super::*;
-
-use crate::dataflow::{AnalysisDomain, GenKill, GenKillAnalysis};
-use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::*;
-use rustc_middle::ty::{ParamEnv, TyCtxt};
-use rustc_span::DUMMY_SP;
-
-pub type MaybeMutBorrowedLocals<'mir, 'tcx> = MaybeBorrowedLocals<MutBorrow<'mir, 'tcx>>;
-
-/// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points
-/// to a given local.
-///
-/// The `K` parameter determines what kind of borrows are tracked. By default,
-/// `MaybeBorrowedLocals` looks for *any* borrow of a local. If you are only interested in borrows
-/// that might allow mutation, use the `MaybeMutBorrowedLocals` type alias instead.
-///
-/// 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. `MaybeMutBorrowedLocals` is used during const checking to prove that a
-/// local has not been mutated via indirect assignment (e.g., `*p = 42`), the side-effects of a
-/// function call or inline assembly.
-pub struct MaybeBorrowedLocals<K = AnyBorrow> {
-    kind: K,
-    ignore_borrow_on_drop: bool,
-}
-
-impl MaybeBorrowedLocals {
-    /// A dataflow analysis that records whether a pointer or reference exists that may alias the
-    /// given local.
-    pub fn all_borrows() -> Self {
-        MaybeBorrowedLocals { kind: AnyBorrow, ignore_borrow_on_drop: false }
-    }
-}
-
-impl MaybeMutBorrowedLocals<'mir, 'tcx> {
-    /// A dataflow analysis that records whether a pointer or reference exists that may *mutably*
-    /// alias the given local.
-    ///
-    /// This includes `&mut` and pointers derived from an `&mut`, as well as shared borrows of
-    /// types with interior mutability.
-    pub fn mut_borrows_only(
-        tcx: TyCtxt<'tcx>,
-        body: &'mir mir::Body<'tcx>,
-        param_env: ParamEnv<'tcx>,
-    ) -> Self {
-        MaybeBorrowedLocals {
-            kind: MutBorrow { body, tcx, param_env },
-            ignore_borrow_on_drop: false,
-        }
-    }
-}
-
-impl<K> MaybeBorrowedLocals<K> {
-    /// During dataflow analysis, ignore the borrow that may occur when a place is dropped.
-    ///
-    /// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut self` as a
-    /// parameter. In the general case, a drop impl could launder that reference into the
-    /// surrounding environment through a raw pointer, thus creating a valid `*mut` pointing to the
-    /// dropped local. We are not yet willing to declare this particular case UB, so we must treat
-    /// all dropped locals as mutably borrowed for now. See discussion on [#61069].
-    ///
-    /// In some contexts, we know that this borrow will never occur. For example, during
-    /// const-eval, custom drop glue cannot be run. Code that calls this should document the
-    /// assumptions that justify ignoring `Drop` terminators in this way.
-    ///
-    /// [#61069]: https://github.com/rust-lang/rust/pull/61069
-    pub fn unsound_ignore_borrow_on_drop(self) -> Self {
-        MaybeBorrowedLocals { ignore_borrow_on_drop: true, ..self }
-    }
-
-    fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T, K> {
-        TransferFunction {
-            kind: &self.kind,
-            trans,
-            ignore_borrow_on_drop: self.ignore_borrow_on_drop,
-        }
-    }
-}
-
-impl<K> AnalysisDomain<'tcx> for MaybeBorrowedLocals<K>
-where
-    K: BorrowAnalysisKind<'tcx>,
-{
-    type Domain = BitSet<Local>;
-    const NAME: &'static str = K::ANALYSIS_NAME;
-
-    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 Self::Domain) {
-        // No locals are aliased on function entry
-    }
-}
-
-impl<K> GenKillAnalysis<'tcx> for MaybeBorrowedLocals<K>
-where
-    K: BorrowAnalysisKind<'tcx>,
-{
-    type Idx = Local;
-
-    fn statement_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        statement: &mir::Statement<'tcx>,
-        location: Location,
-    ) {
-        self.transfer_function(trans).visit_statement(statement, location);
-    }
-
-    fn terminator_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        terminator: &mir::Terminator<'tcx>,
-        location: Location,
-    ) {
-        self.transfer_function(trans).visit_terminator(terminator, location);
-    }
-
-    fn call_return_effect(
-        &self,
-        _trans: &mut impl GenKill<Self::Idx>,
-        _block: mir::BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        _dest_place: mir::Place<'tcx>,
-    ) {
-    }
-}
-
-/// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`.
-struct TransferFunction<'a, T, K> {
-    trans: &'a mut T,
-    kind: &'a K,
-    ignore_borrow_on_drop: bool,
-}
-
-impl<T, K> Visitor<'tcx> for TransferFunction<'a, T, K>
-where
-    T: GenKill<Local>,
-    K: BorrowAnalysisKind<'tcx>,
-{
-    fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) {
-        self.super_statement(stmt, location);
-
-        // When we reach a `StorageDead` statement, we can assume that any pointers to this memory
-        // are now invalid.
-        if let StatementKind::StorageDead(local) = stmt.kind {
-            self.trans.kill(local);
-        }
-    }
-
-    fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
-        self.super_rvalue(rvalue, location);
-
-        match rvalue {
-            mir::Rvalue::AddressOf(mt, borrowed_place) => {
-                if !borrowed_place.is_indirect() && self.kind.in_address_of(*mt, *borrowed_place) {
-                    self.trans.gen(borrowed_place.local);
-                }
-            }
-
-            mir::Rvalue::Ref(_, kind, borrowed_place) => {
-                if !borrowed_place.is_indirect() && self.kind.in_ref(*kind, *borrowed_place) {
-                    self.trans.gen(borrowed_place.local);
-                }
-            }
-
-            mir::Rvalue::Cast(..)
-            | mir::Rvalue::Use(..)
-            | mir::Rvalue::ThreadLocalRef(..)
-            | mir::Rvalue::Repeat(..)
-            | mir::Rvalue::Len(..)
-            | mir::Rvalue::BinaryOp(..)
-            | mir::Rvalue::CheckedBinaryOp(..)
-            | mir::Rvalue::NullaryOp(..)
-            | mir::Rvalue::UnaryOp(..)
-            | mir::Rvalue::Discriminant(..)
-            | mir::Rvalue::Aggregate(..) => {}
-        }
-    }
-
-    fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
-        self.super_terminator(terminator, location);
-
-        match terminator.kind {
-            mir::TerminatorKind::Drop { place: dropped_place, .. }
-            | mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
-                // See documentation for `unsound_ignore_borrow_on_drop` for an explanation.
-                if !self.ignore_borrow_on_drop {
-                    self.trans.gen(dropped_place.local);
-                }
-            }
-
-            TerminatorKind::Abort
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::Call { .. }
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. }
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::Goto { .. }
-            | TerminatorKind::InlineAsm { .. }
-            | TerminatorKind::Resume
-            | TerminatorKind::Return
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::Unreachable
-            | TerminatorKind::Yield { .. } => {}
-        }
-    }
-}
-
-pub struct AnyBorrow;
-
-pub struct MutBorrow<'mir, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    body: &'mir Body<'tcx>,
-    param_env: ParamEnv<'tcx>,
-}
-
-impl MutBorrow<'mir, 'tcx> {
-    /// `&` and `&raw` only allow mutation if the borrowed place is `!Freeze`.
-    ///
-    /// This assumes that it is UB to take the address of a struct field whose type is
-    /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of
-    /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will
-    /// have to check the type of the borrowed **local** instead of the borrowed **place**
-    /// below. See [rust-lang/unsafe-code-guidelines#134].
-    ///
-    /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
-    fn shared_borrow_allows_mutation(&self, place: Place<'tcx>) -> bool {
-        !place.ty(self.body, self.tcx).ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env)
-    }
-}
-
-pub trait BorrowAnalysisKind<'tcx> {
-    const ANALYSIS_NAME: &'static str;
-
-    fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool;
-    fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool;
-}
-
-impl BorrowAnalysisKind<'tcx> for AnyBorrow {
-    const ANALYSIS_NAME: &'static str = "maybe_borrowed_locals";
-
-    fn in_ref(&self, _: mir::BorrowKind, _: Place<'_>) -> bool {
-        true
-    }
-    fn in_address_of(&self, _: Mutability, _: Place<'_>) -> bool {
-        true
-    }
-}
-
-impl BorrowAnalysisKind<'tcx> for MutBorrow<'mir, 'tcx> {
-    const ANALYSIS_NAME: &'static str = "maybe_mut_borrowed_locals";
-
-    fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool {
-        match kind {
-            mir::BorrowKind::Mut { .. } => true,
-            mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {
-                self.shared_borrow_allows_mutation(place)
-            }
-        }
-    }
-
-    fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool {
-        match mt {
-            Mutability::Mut => true,
-            Mutability::Not => self.shared_borrow_allows_mutation(place),
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/dataflow/impls/init_locals.rs b/compiler/rustc_mir/src/dataflow/impls/init_locals.rs
deleted file mode 100644
index bb7292cd033..00000000000
--- a/compiler/rustc_mir/src/dataflow/impls/init_locals.rs
+++ /dev/null
@@ -1,113 +0,0 @@
-//! A less precise version of `MaybeInitializedPlaces` whose domain is entire locals.
-//!
-//! A local will be maybe initialized if *any* projections of that local might be initialized.
-
-use crate::dataflow::{self, GenKill};
-
-use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::visit::{PlaceContext, Visitor};
-use rustc_middle::mir::{self, BasicBlock, Local, Location};
-
-pub struct MaybeInitializedLocals;
-
-impl dataflow::AnalysisDomain<'tcx> for MaybeInitializedLocals {
-    type Domain = BitSet<Local>;
-
-    const NAME: &'static str = "maybe_init_locals";
-
-    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 Self::Domain) {
-        // Function arguments are initialized to begin with.
-        for arg in body.args_iter() {
-            entry_set.insert(arg);
-        }
-    }
-}
-
-impl dataflow::GenKillAnalysis<'tcx> for MaybeInitializedLocals {
-    type Idx = Local;
-
-    fn statement_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        statement: &mir::Statement<'tcx>,
-        loc: Location,
-    ) {
-        TransferFunction { trans }.visit_statement(statement, loc)
-    }
-
-    fn terminator_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        terminator: &mir::Terminator<'tcx>,
-        loc: Location,
-    ) {
-        TransferFunction { trans }.visit_terminator(terminator, loc)
-    }
-
-    fn call_return_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _block: BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        return_place: mir::Place<'tcx>,
-    ) {
-        trans.gen(return_place.local)
-    }
-
-    /// See `Analysis::apply_yield_resume_effect`.
-    fn yield_resume_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _resume_block: BasicBlock,
-        resume_place: mir::Place<'tcx>,
-    ) {
-        trans.gen(resume_place.local)
-    }
-}
-
-struct TransferFunction<'a, T> {
-    trans: &'a mut T,
-}
-
-impl<T> Visitor<'tcx> for TransferFunction<'a, T>
-where
-    T: GenKill<Local>,
-{
-    fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
-        use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, NonUseContext};
-        match context {
-            // These are handled specially in `call_return_effect` and `yield_resume_effect`.
-            PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => {}
-
-            // Otherwise, when a place is mutated, we must consider it possibly initialized.
-            PlaceContext::MutatingUse(_) => self.trans.gen(local),
-
-            // If the local is moved out of, or if it gets marked `StorageDead`, consider it no
-            // longer initialized.
-            PlaceContext::NonUse(NonUseContext::StorageDead)
-            | PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => self.trans.kill(local),
-
-            // All other uses do not affect this analysis.
-            PlaceContext::NonUse(
-                NonUseContext::StorageLive
-                | NonUseContext::AscribeUserTy
-                | NonUseContext::VarDebugInfo,
-            )
-            | PlaceContext::NonMutatingUse(
-                NonMutatingUseContext::Inspect
-                | NonMutatingUseContext::Copy
-                | NonMutatingUseContext::SharedBorrow
-                | NonMutatingUseContext::ShallowBorrow
-                | NonMutatingUseContext::UniqueBorrow
-                | NonMutatingUseContext::AddressOf
-                | NonMutatingUseContext::Projection,
-            ) => {}
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/dataflow/impls/liveness.rs b/compiler/rustc_mir/src/dataflow/impls/liveness.rs
deleted file mode 100644
index 2d20f0d9547..00000000000
--- a/compiler/rustc_mir/src/dataflow/impls/liveness.rs
+++ /dev/null
@@ -1,165 +0,0 @@
-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, GenKill, GenKillAnalysis};
-
-/// A [live-variable dataflow analysis][liveness].
-///
-/// This analysis considers references as being used only at the point of the
-/// borrow. In other words, this analysis does not track uses because of references that already
-/// exist. See [this `mir-dataflow` test][flow-test] for an example. You almost never want to use
-/// this analysis without also looking at the results of [`MaybeBorrowedLocals`].
-///
-/// [`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
-pub struct MaybeLiveLocals;
-
-impl MaybeLiveLocals {
-    fn transfer_function<T>(&self, trans: &'a mut T) -> TransferFunction<'a, T> {
-        TransferFunction(trans)
-    }
-}
-
-impl AnalysisDomain<'tcx> for MaybeLiveLocals {
-    type Domain = BitSet<Local>;
-    type Direction = Backward;
-
-    const NAME: &'static str = "liveness";
-
-    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 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>,
-        statement: &mir::Statement<'tcx>,
-        location: Location,
-    ) {
-        self.transfer_function(trans).visit_statement(statement, location);
-    }
-
-    fn terminator_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        terminator: &mir::Terminator<'tcx>,
-        location: Location,
-    ) {
-        self.transfer_function(trans).visit_terminator(terminator, location);
-    }
-
-    fn call_return_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _block: mir::BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        dest_place: mir::Place<'tcx>,
-    ) {
-        if let Some(local) = dest_place.as_local() {
-            trans.kill(local);
-        }
-    }
-
-    fn yield_resume_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _resume_block: mir::BasicBlock,
-        resume_place: mir::Place<'tcx>,
-    ) {
-        if let Some(local) = resume_place.as_local() {
-            trans.kill(local);
-        }
-    }
-}
-
-struct TransferFunction<'a, T>(&'a mut T);
-
-impl<'tcx, T> Visitor<'tcx> for TransferFunction<'_, T>
-where
-    T: GenKill<Local>,
-{
-    fn visit_place(&mut self, place: &mir::Place<'tcx>, context: PlaceContext, location: Location) {
-        let mir::Place { projection, local } = *place;
-
-        // We purposefully do not call `super_place` here to avoid calling `visit_local` for this
-        // place with one of the `Projection` variants of `PlaceContext`.
-        self.visit_projection(place.as_ref(), context, location);
-
-        match DefUse::for_place(context) {
-            // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use.
-            Some(_) if place.is_indirect() => self.0.gen(local),
-
-            Some(DefUse::Def) if projection.is_empty() => self.0.kill(local),
-            Some(DefUse::Use) => self.0.gen(local),
-            _ => {}
-        }
-    }
-
-    fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
-        // Because we do not call `super_place` above, `visit_local` is only called for locals that
-        // do not appear as part of  a `Place` in the MIR. This handles cases like the implicit use
-        // of the return place in a `Return` terminator or the index in an `Index` projection.
-        match DefUse::for_place(context) {
-            Some(DefUse::Def) => self.0.kill(local),
-            Some(DefUse::Use) => self.0.gen(local),
-            _ => {}
-        }
-    }
-}
-
-#[derive(Eq, PartialEq, Clone)]
-enum DefUse {
-    Def,
-    Use,
-}
-
-impl DefUse {
-    fn for_place(context: PlaceContext) -> Option<DefUse> {
-        match context {
-            PlaceContext::NonUse(_) => None,
-
-            PlaceContext::MutatingUse(MutatingUseContext::Store) => Some(DefUse::Def),
-
-            // `MutatingUseContext::Call` and `MutatingUseContext::Yield` indicate that this is the
-            // destination place for a `Call` return or `Yield` resume respectively. Since this is
-            // only a `Def` when the function returns successfully, we handle this case separately
-            // in `call_return_effect` above.
-            PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => None,
-
-            // All other contexts are uses...
-            PlaceContext::MutatingUse(
-                MutatingUseContext::AddressOf
-                | MutatingUseContext::AsmOutput
-                | MutatingUseContext::Borrow
-                | MutatingUseContext::Drop
-                | MutatingUseContext::Retag,
-            )
-            | PlaceContext::NonMutatingUse(
-                NonMutatingUseContext::AddressOf
-                | NonMutatingUseContext::Copy
-                | NonMutatingUseContext::Inspect
-                | NonMutatingUseContext::Move
-                | NonMutatingUseContext::ShallowBorrow
-                | NonMutatingUseContext::SharedBorrow
-                | NonMutatingUseContext::UniqueBorrow,
-            ) => Some(DefUse::Use),
-
-            PlaceContext::MutatingUse(MutatingUseContext::Projection)
-            | PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => {
-                unreachable!("A projection could be a def or a use and must be handled separately")
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/dataflow/impls/mod.rs b/compiler/rustc_mir/src/dataflow/impls/mod.rs
deleted file mode 100644
index 020a7b188fd..00000000000
--- a/compiler/rustc_mir/src/dataflow/impls/mod.rs
+++ /dev/null
@@ -1,715 +0,0 @@
-//! Dataflow analyses are built upon some interpretation of the
-//! bitvectors attached to each basic block, represented via a
-//! zero-sized structure.
-
-use rustc_index::bit_set::BitSet;
-use rustc_index::vec::Idx;
-use rustc_middle::mir::{self, Body, Location};
-use rustc_middle::ty::{self, TyCtxt};
-
-use super::MoveDataParamEnv;
-
-use crate::util::elaborate_drops::DropFlagState;
-
-use super::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex};
-use super::{lattice, AnalysisDomain, GenKill, GenKillAnalysis};
-
-use super::drop_flag_effects_for_function_entry;
-use super::drop_flag_effects_for_location;
-use super::on_lookup_result_bits;
-use crate::dataflow::drop_flag_effects;
-use crate::dataflow::framework::SwitchIntEdgeEffects;
-
-mod borrowed_locals;
-mod init_locals;
-mod liveness;
-mod storage_liveness;
-
-pub use self::borrowed_locals::{MaybeBorrowedLocals, MaybeMutBorrowedLocals};
-pub use self::init_locals::MaybeInitializedLocals;
-pub use self::liveness::MaybeLiveLocals;
-pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive};
-
-/// `MaybeInitializedPlaces` tracks all places that might be
-/// initialized upon reaching a particular point in the control flow
-/// for a function.
-///
-/// For example, in code like the following, we have corresponding
-/// dataflow information shown in the right-hand comments.
-///
-/// ```rust
-/// struct S;
-/// fn foo(pred: bool) {                       // maybe-init:
-///                                            // {}
-///     let a = S; let b = S; let c; let d;    // {a, b}
-///
-///     if pred {
-///         drop(a);                           // {   b}
-///         b = S;                             // {   b}
-///
-///     } else {
-///         drop(b);                           // {a}
-///         d = S;                             // {a,       d}
-///
-///     }                                      // {a, b,    d}
-///
-///     c = S;                                 // {a, b, c, d}
-/// }
-/// ```
-///
-/// To determine whether a place *must* be initialized at a
-/// particular control-flow point, one can take the set-difference
-/// between this data and the data from `MaybeUninitializedPlaces` at the
-/// corresponding control-flow point.
-///
-/// Similarly, at a given `drop` statement, the set-intersection
-/// between this data and `MaybeUninitializedPlaces` yields the set of
-/// places that would require a dynamic drop-flag at that statement.
-pub struct MaybeInitializedPlaces<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    body: &'a Body<'tcx>,
-    mdpe: &'a MoveDataParamEnv<'tcx>,
-}
-
-impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self {
-        MaybeInitializedPlaces { tcx, body, mdpe }
-    }
-}
-
-impl<'a, 'tcx> HasMoveData<'tcx> for MaybeInitializedPlaces<'a, 'tcx> {
-    fn move_data(&self) -> &MoveData<'tcx> {
-        &self.mdpe.move_data
-    }
-}
-
-/// `MaybeUninitializedPlaces` tracks all places that might be
-/// uninitialized upon reaching a particular point in the control flow
-/// for a function.
-///
-/// For example, in code like the following, we have corresponding
-/// dataflow information shown in the right-hand comments.
-///
-/// ```rust
-/// struct S;
-/// fn foo(pred: bool) {                       // maybe-uninit:
-///                                            // {a, b, c, d}
-///     let a = S; let b = S; let c; let d;    // {      c, d}
-///
-///     if pred {
-///         drop(a);                           // {a,    c, d}
-///         b = S;                             // {a,    c, d}
-///
-///     } else {
-///         drop(b);                           // {   b, c, d}
-///         d = S;                             // {   b, c   }
-///
-///     }                                      // {a, b, c, d}
-///
-///     c = S;                                 // {a, b,    d}
-/// }
-/// ```
-///
-/// To determine whether a place *must* be uninitialized at a
-/// particular control-flow point, one can take the set-difference
-/// between this data and the data from `MaybeInitializedPlaces` at the
-/// corresponding control-flow point.
-///
-/// Similarly, at a given `drop` statement, the set-intersection
-/// between this data and `MaybeInitializedPlaces` yields the set of
-/// places that would require a dynamic drop-flag at that statement.
-pub struct MaybeUninitializedPlaces<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    body: &'a Body<'tcx>,
-    mdpe: &'a MoveDataParamEnv<'tcx>,
-
-    mark_inactive_variants_as_uninit: bool,
-}
-
-impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self {
-        MaybeUninitializedPlaces { tcx, body, mdpe, mark_inactive_variants_as_uninit: false }
-    }
-
-    /// Causes inactive enum variants to be marked as "maybe uninitialized" after a switch on an
-    /// enum discriminant.
-    ///
-    /// This is correct in a vacuum but is not the default because it causes problems in the borrow
-    /// checker, where this information gets propagated along `FakeEdge`s.
-    pub fn mark_inactive_variants_as_uninit(mut self) -> Self {
-        self.mark_inactive_variants_as_uninit = true;
-        self
-    }
-}
-
-impl<'a, 'tcx> HasMoveData<'tcx> for MaybeUninitializedPlaces<'a, 'tcx> {
-    fn move_data(&self) -> &MoveData<'tcx> {
-        &self.mdpe.move_data
-    }
-}
-
-/// `DefinitelyInitializedPlaces` tracks all places that are definitely
-/// initialized upon reaching a particular point in the control flow
-/// for a function.
-///
-/// For example, in code like the following, we have corresponding
-/// dataflow information shown in the right-hand comments.
-///
-/// ```rust
-/// struct S;
-/// fn foo(pred: bool) {                       // definite-init:
-///                                            // {          }
-///     let a = S; let b = S; let c; let d;    // {a, b      }
-///
-///     if pred {
-///         drop(a);                           // {   b,     }
-///         b = S;                             // {   b,     }
-///
-///     } else {
-///         drop(b);                           // {a,        }
-///         d = S;                             // {a,       d}
-///
-///     }                                      // {          }
-///
-///     c = S;                                 // {       c  }
-/// }
-/// ```
-///
-/// To determine whether a place *may* be uninitialized at a
-/// particular control-flow point, one can take the set-complement
-/// of this data.
-///
-/// Similarly, at a given `drop` statement, the set-difference between
-/// this data and `MaybeInitializedPlaces` yields the set of places
-/// that would require a dynamic drop-flag at that statement.
-pub struct DefinitelyInitializedPlaces<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    body: &'a Body<'tcx>,
-    mdpe: &'a MoveDataParamEnv<'tcx>,
-}
-
-impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self {
-        DefinitelyInitializedPlaces { tcx, body, mdpe }
-    }
-}
-
-impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
-    fn move_data(&self) -> &MoveData<'tcx> {
-        &self.mdpe.move_data
-    }
-}
-
-/// `EverInitializedPlaces` tracks all places that might have ever been
-/// initialized upon reaching a particular point in the control flow
-/// for a function, without an intervening `StorageDead`.
-///
-/// This dataflow is used to determine if an immutable local variable may
-/// be assigned to.
-///
-/// For example, in code like the following, we have corresponding
-/// dataflow information shown in the right-hand comments.
-///
-/// ```rust
-/// struct S;
-/// fn foo(pred: bool) {                       // ever-init:
-///                                            // {          }
-///     let a = S; let b = S; let c; let d;    // {a, b      }
-///
-///     if pred {
-///         drop(a);                           // {a, b,     }
-///         b = S;                             // {a, b,     }
-///
-///     } else {
-///         drop(b);                           // {a, b,      }
-///         d = S;                             // {a, b,    d }
-///
-///     }                                      // {a, b,    d }
-///
-///     c = S;                                 // {a, b, c, d }
-/// }
-/// ```
-pub struct EverInitializedPlaces<'a, 'tcx> {
-    #[allow(dead_code)]
-    tcx: TyCtxt<'tcx>,
-    body: &'a Body<'tcx>,
-    mdpe: &'a MoveDataParamEnv<'tcx>,
-}
-
-impl<'a, 'tcx> EverInitializedPlaces<'a, 'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, mdpe: &'a MoveDataParamEnv<'tcx>) -> Self {
-        EverInitializedPlaces { tcx, body, mdpe }
-    }
-}
-
-impl<'a, 'tcx> HasMoveData<'tcx> for EverInitializedPlaces<'a, 'tcx> {
-    fn move_data(&self) -> &MoveData<'tcx> {
-        &self.mdpe.move_data
-    }
-}
-
-impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> {
-    fn update_bits(
-        trans: &mut impl GenKill<MovePathIndex>,
-        path: MovePathIndex,
-        state: DropFlagState,
-    ) {
-        match state {
-            DropFlagState::Absent => trans.kill(path),
-            DropFlagState::Present => trans.gen(path),
-        }
-    }
-}
-
-impl<'a, 'tcx> MaybeUninitializedPlaces<'a, 'tcx> {
-    fn update_bits(
-        trans: &mut impl GenKill<MovePathIndex>,
-        path: MovePathIndex,
-        state: DropFlagState,
-    ) {
-        match state {
-            DropFlagState::Absent => trans.gen(path),
-            DropFlagState::Present => trans.kill(path),
-        }
-    }
-}
-
-impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> {
-    fn update_bits(
-        trans: &mut impl GenKill<MovePathIndex>,
-        path: MovePathIndex,
-        state: DropFlagState,
-    ) {
-        match state {
-            DropFlagState::Absent => trans.kill(path),
-            DropFlagState::Present => trans.gen(path),
-        }
-    }
-}
-
-impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
-    type Domain = BitSet<MovePathIndex>;
-    const NAME: &'static str = "maybe_init";
-
-    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 Self::Domain) {
-        drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| {
-            assert!(s == DropFlagState::Present);
-            state.insert(path);
-        });
-    }
-}
-
-impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> {
-    type Idx = MovePathIndex;
-
-    fn statement_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _statement: &mir::Statement<'tcx>,
-        location: Location,
-    ) {
-        drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
-            Self::update_bits(trans, path, s)
-        })
-    }
-
-    fn terminator_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _terminator: &mir::Terminator<'tcx>,
-        location: Location,
-    ) {
-        drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
-            Self::update_bits(trans, path, s)
-        })
-    }
-
-    fn call_return_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _block: mir::BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        dest_place: mir::Place<'tcx>,
-    ) {
-        // when a call returns successfully, that means we need to set
-        // the bits for that dest_place to 1 (initialized).
-        on_lookup_result_bits(
-            self.tcx,
-            self.body,
-            self.move_data(),
-            self.move_data().rev_lookup.find(dest_place.as_ref()),
-            |mpi| {
-                trans.gen(mpi);
-            },
-        );
-    }
-
-    fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
-        &self,
-        block: mir::BasicBlock,
-        discr: &mir::Operand<'tcx>,
-        edge_effects: &mut impl SwitchIntEdgeEffects<G>,
-    ) {
-        if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration {
-            return;
-        }
-
-        let enum_ = discr.place().and_then(|discr| {
-            switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr)
-        });
-
-        let (enum_place, enum_def) = match enum_ {
-            Some(x) => x,
-            None => return,
-        };
-
-        let mut discriminants = enum_def.discriminants(self.tcx);
-        edge_effects.apply(|trans, edge| {
-            let value = match edge.value {
-                Some(x) => x,
-                None => return,
-            };
-
-            // MIR building adds discriminants to the `values` array in the same order as they
-            // are yielded by `AdtDef::discriminants`. We rely on this to match each
-            // discriminant in `values` to its corresponding variant in linear time.
-            let (variant, _) = discriminants
-                .find(|&(_, discr)| discr.val == value)
-                .expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`");
-
-            // Kill all move paths that correspond to variants we know to be inactive along this
-            // particular outgoing edge of a `SwitchInt`.
-            drop_flag_effects::on_all_inactive_variants(
-                self.tcx,
-                self.body,
-                self.move_data(),
-                enum_place,
-                variant,
-                |mpi| trans.kill(mpi),
-            );
-        });
-    }
-}
-
-impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
-    type Domain = BitSet<MovePathIndex>;
-
-    const NAME: &'static str = "maybe_uninit";
-
-    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, _: &mir::Body<'tcx>, state: &mut Self::Domain) {
-        // set all bits to 1 (uninit) before gathering counterevidence
-        state.insert_all();
-
-        drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| {
-            assert!(s == DropFlagState::Present);
-            state.remove(path);
-        });
-    }
-}
-
-impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> {
-    type Idx = MovePathIndex;
-
-    fn statement_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _statement: &mir::Statement<'tcx>,
-        location: Location,
-    ) {
-        drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
-            Self::update_bits(trans, path, s)
-        })
-    }
-
-    fn terminator_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _terminator: &mir::Terminator<'tcx>,
-        location: Location,
-    ) {
-        drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
-            Self::update_bits(trans, path, s)
-        })
-    }
-
-    fn call_return_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _block: mir::BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        dest_place: mir::Place<'tcx>,
-    ) {
-        // when a call returns successfully, that means we need to set
-        // the bits for that dest_place to 0 (initialized).
-        on_lookup_result_bits(
-            self.tcx,
-            self.body,
-            self.move_data(),
-            self.move_data().rev_lookup.find(dest_place.as_ref()),
-            |mpi| {
-                trans.kill(mpi);
-            },
-        );
-    }
-
-    fn switch_int_edge_effects<G: GenKill<Self::Idx>>(
-        &self,
-        block: mir::BasicBlock,
-        discr: &mir::Operand<'tcx>,
-        edge_effects: &mut impl SwitchIntEdgeEffects<G>,
-    ) {
-        if !self.tcx.sess.opts.debugging_opts.precise_enum_drop_elaboration {
-            return;
-        }
-
-        if !self.mark_inactive_variants_as_uninit {
-            return;
-        }
-
-        let enum_ = discr.place().and_then(|discr| {
-            switch_on_enum_discriminant(self.tcx, &self.body, &self.body[block], discr)
-        });
-
-        let (enum_place, enum_def) = match enum_ {
-            Some(x) => x,
-            None => return,
-        };
-
-        let mut discriminants = enum_def.discriminants(self.tcx);
-        edge_effects.apply(|trans, edge| {
-            let value = match edge.value {
-                Some(x) => x,
-                None => return,
-            };
-
-            // MIR building adds discriminants to the `values` array in the same order as they
-            // are yielded by `AdtDef::discriminants`. We rely on this to match each
-            // discriminant in `values` to its corresponding variant in linear time.
-            let (variant, _) = discriminants
-                .find(|&(_, discr)| discr.val == value)
-                .expect("Order of `AdtDef::discriminants` differed from `SwitchInt::values`");
-
-            // Mark all move paths that correspond to variants other than this one as maybe
-            // uninitialized (in reality, they are *definitely* uninitialized).
-            drop_flag_effects::on_all_inactive_variants(
-                self.tcx,
-                self.body,
-                self.move_data(),
-                enum_place,
-                variant,
-                |mpi| trans.gen(mpi),
-            );
-        });
-    }
-}
-
-impl<'a, 'tcx> AnalysisDomain<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> {
-    /// Use set intersection as the join operator.
-    type Domain = lattice::Dual<BitSet<MovePathIndex>>;
-
-    const NAME: &'static str = "definite_init";
-
-    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 Self::Domain) {
-        state.0.clear();
-
-        drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| {
-            assert!(s == DropFlagState::Present);
-            state.0.insert(path);
-        });
-    }
-}
-
-impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> {
-    type Idx = MovePathIndex;
-
-    fn statement_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _statement: &mir::Statement<'tcx>,
-        location: Location,
-    ) {
-        drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
-            Self::update_bits(trans, path, s)
-        })
-    }
-
-    fn terminator_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _terminator: &mir::Terminator<'tcx>,
-        location: Location,
-    ) {
-        drop_flag_effects_for_location(self.tcx, self.body, self.mdpe, location, |path, s| {
-            Self::update_bits(trans, path, s)
-        })
-    }
-
-    fn call_return_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _block: mir::BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        dest_place: mir::Place<'tcx>,
-    ) {
-        // when a call returns successfully, that means we need to set
-        // the bits for that dest_place to 1 (initialized).
-        on_lookup_result_bits(
-            self.tcx,
-            self.body,
-            self.move_data(),
-            self.move_data().rev_lookup.find(dest_place.as_ref()),
-            |mpi| {
-                trans.gen(mpi);
-            },
-        );
-    }
-}
-
-impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> {
-    type Domain = BitSet<InitIndex>;
-
-    const NAME: &'static str = "ever_init";
-
-    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 Self::Domain) {
-        for arg_init in 0..body.arg_count {
-            state.insert(InitIndex::new(arg_init));
-        }
-    }
-}
-
-impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> {
-    type Idx = InitIndex;
-
-    fn statement_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        stmt: &mir::Statement<'tcx>,
-        location: Location,
-    ) {
-        let move_data = self.move_data();
-        let init_path_map = &move_data.init_path_map;
-        let init_loc_map = &move_data.init_loc_map;
-        let rev_lookup = &move_data.rev_lookup;
-
-        debug!(
-            "statement {:?} at loc {:?} initializes move_indexes {:?}",
-            stmt, location, &init_loc_map[location]
-        );
-        trans.gen_all(init_loc_map[location].iter().copied());
-
-        if let mir::StatementKind::StorageDead(local) = stmt.kind {
-            // End inits for StorageDead, so that an immutable variable can
-            // be reinitialized on the next iteration of the loop.
-            let move_path_index = rev_lookup.find_local(local);
-            debug!(
-                "stmt {:?} at loc {:?} clears the ever initialized status of {:?}",
-                stmt, location, &init_path_map[move_path_index]
-            );
-            trans.kill_all(init_path_map[move_path_index].iter().copied());
-        }
-    }
-
-    fn terminator_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _terminator: &mir::Terminator<'tcx>,
-        location: Location,
-    ) {
-        let (body, move_data) = (self.body, self.move_data());
-        let term = body[location.block].terminator();
-        let init_loc_map = &move_data.init_loc_map;
-        debug!(
-            "terminator {:?} at loc {:?} initializes move_indexes {:?}",
-            term, location, &init_loc_map[location]
-        );
-        trans.gen_all(
-            init_loc_map[location]
-                .iter()
-                .filter(|init_index| {
-                    move_data.inits[**init_index].kind != InitKind::NonPanicPathOnly
-                })
-                .copied(),
-        );
-    }
-
-    fn call_return_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        block: mir::BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        _dest_place: mir::Place<'tcx>,
-    ) {
-        let move_data = self.move_data();
-        let init_loc_map = &move_data.init_loc_map;
-
-        let call_loc = self.body.terminator_loc(block);
-        for init_index in &init_loc_map[call_loc] {
-            trans.gen(*init_index);
-        }
-    }
-}
-
-/// Inspect a `SwitchInt`-terminated basic block to see if the condition of that `SwitchInt` is
-/// an enum discriminant.
-///
-/// We expect such blocks to have a call to `discriminant` as their last statement like so:
-///
-/// ```text
-/// ...
-/// _42 = discriminant(_1)
-/// SwitchInt(_42, ..)
-/// ```
-///
-/// If the basic block matches this pattern, this function returns the place corresponding to the
-/// enum (`_1` in the example above) as well as the `AdtDef` of that enum.
-fn switch_on_enum_discriminant(
-    tcx: TyCtxt<'tcx>,
-    body: &'mir mir::Body<'tcx>,
-    block: &'mir mir::BasicBlockData<'tcx>,
-    switch_on: mir::Place<'tcx>,
-) -> Option<(mir::Place<'tcx>, &'tcx ty::AdtDef)> {
-    match block.statements.last().map(|stmt| &stmt.kind) {
-        Some(mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated))))
-            if *lhs == switch_on =>
-        {
-            match &discriminated.ty(body, tcx).ty.kind() {
-                ty::Adt(def, _) => Some((*discriminated, def)),
-
-                // `Rvalue::Discriminant` is also used to get the active yield point for a
-                // generator, but we do not need edge-specific effects in that case. This may
-                // change in the future.
-                ty::Generator(..) => None,
-
-                t => bug!("`discriminant` called on unexpected type {:?}", t),
-            }
-        }
-
-        _ => None,
-    }
-}
diff --git a/compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs b/compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs
deleted file mode 100644
index 792664597fd..00000000000
--- a/compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs
+++ /dev/null
@@ -1,307 +0,0 @@
-pub use super::*;
-
-use crate::dataflow::{self, GenKill, Results, ResultsRefCursor};
-use crate::util::storage::AlwaysLiveLocals;
-use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::*;
-use std::cell::RefCell;
-
-#[derive(Clone)]
-pub struct MaybeStorageLive {
-    always_live_locals: AlwaysLiveLocals,
-}
-
-impl MaybeStorageLive {
-    pub fn new(always_live_locals: AlwaysLiveLocals) -> Self {
-        MaybeStorageLive { always_live_locals }
-    }
-}
-
-impl dataflow::AnalysisDomain<'tcx> for MaybeStorageLive {
-    type Domain = BitSet<Local>;
-
-    const NAME: &'static str = "maybe_storage_live";
-
-    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 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);
-        }
-
-        for arg in body.args_iter() {
-            on_entry.insert(arg);
-        }
-    }
-}
-
-impl dataflow::GenKillAnalysis<'tcx> for MaybeStorageLive {
-    type Idx = Local;
-
-    fn statement_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        stmt: &mir::Statement<'tcx>,
-        _: Location,
-    ) {
-        match stmt.kind {
-            StatementKind::StorageLive(l) => trans.gen(l),
-            StatementKind::StorageDead(l) => trans.kill(l),
-            _ => (),
-        }
-    }
-
-    fn terminator_effect(
-        &self,
-        _trans: &mut impl GenKill<Self::Idx>,
-        _: &mir::Terminator<'tcx>,
-        _: Location,
-    ) {
-        // Terminators have no effect
-    }
-
-    fn call_return_effect(
-        &self,
-        _trans: &mut impl GenKill<Self::Idx>,
-        _block: BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        _return_place: mir::Place<'tcx>,
-    ) {
-        // Nothing to do when a call returns successfully
-    }
-}
-
-type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, '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>>,
-}
-
-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<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
-    type Domain = BitSet<Local>;
-
-    const NAME: &'static str = "requires_storage";
-
-    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 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) {
-            on_entry.insert(arg);
-        }
-    }
-}
-
-impl<'mir, 'tcx> dataflow::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
-    type Idx = Local;
-
-    fn before_statement_effect(
-        &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);
-
-        match &stmt.kind {
-            StatementKind::StorageDead(l) => trans.kill(*l),
-
-            // If a place is assigned to in a statement, it needs storage for that statement.
-            StatementKind::Assign(box (place, _))
-            | StatementKind::SetDiscriminant { box place, .. } => {
-                trans.gen(place.local);
-            }
-            StatementKind::LlvmInlineAsm(asm) => {
-                for place in &*asm.outputs {
-                    trans.gen(place.local);
-                }
-            }
-
-            // Nothing to do for these. Match exhaustively so this fails to compile when new
-            // variants are added.
-            StatementKind::AscribeUserType(..)
-            | StatementKind::Coverage(..)
-            | StatementKind::FakeRead(..)
-            | StatementKind::Nop
-            | StatementKind::Retag(..)
-            | StatementKind::CopyNonOverlapping(..)
-            | StatementKind::StorageLive(..) => {}
-        }
-    }
-
-    fn statement_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _: &mir::Statement<'tcx>,
-        loc: Location,
-    ) {
-        // If we move from a place then only stops needing storage *after*
-        // that statement.
-        self.check_for_move(trans, loc);
-    }
-
-    fn before_terminator_effect(
-        &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);
-
-        match &terminator.kind {
-            TerminatorKind::Call { destination: Some((place, _)), .. } => {
-                trans.gen(place.local);
-            }
-
-            // Note that we do *not* gen the `resume_arg` of `Yield` terminators. The reason for
-            // that is that a `yield` will return from the function, and `resume_arg` is written
-            // only when the generator is later resumed. Unlike `Call`, this doesn't require the
-            // place to have storage *before* the yield, only after.
-            TerminatorKind::Yield { .. } => {}
-
-            TerminatorKind::InlineAsm { operands, .. } => {
-                for op in operands {
-                    match op {
-                        InlineAsmOperand::Out { place, .. }
-                        | InlineAsmOperand::InOut { out_place: place, .. } => {
-                            if let Some(place) = place {
-                                trans.gen(place.local);
-                            }
-                        }
-                        InlineAsmOperand::In { .. }
-                        | InlineAsmOperand::Const { .. }
-                        | InlineAsmOperand::SymFn { .. }
-                        | InlineAsmOperand::SymStatic { .. } => {}
-                    }
-                }
-            }
-
-            // Nothing to do for these. Match exhaustively so this fails to compile when new
-            // variants are added.
-            TerminatorKind::Call { destination: None, .. }
-            | TerminatorKind::Abort
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::Drop { .. }
-            | TerminatorKind::DropAndReplace { .. }
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. }
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::Goto { .. }
-            | TerminatorKind::Resume
-            | TerminatorKind::Return
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::Unreachable => {}
-        }
-    }
-
-    fn terminator_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        terminator: &mir::Terminator<'tcx>,
-        loc: Location,
-    ) {
-        match &terminator.kind {
-            // For call terminators the destination requires storage for the call
-            // and after the call returns successfully, but not after a panic.
-            // Since `propagate_call_unwind` doesn't exist, we have to kill the
-            // destination here, and then gen it again in `call_return_effect`.
-            TerminatorKind::Call { destination: Some((place, _)), .. } => {
-                trans.kill(place.local);
-            }
-
-            // Nothing to do for these. Match exhaustively so this fails to compile when new
-            // variants are added.
-            TerminatorKind::Call { destination: None, .. }
-            | TerminatorKind::Yield { .. }
-            | TerminatorKind::Abort
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::Drop { .. }
-            | TerminatorKind::DropAndReplace { .. }
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. }
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::Goto { .. }
-            | TerminatorKind::InlineAsm { .. }
-            | TerminatorKind::Resume
-            | TerminatorKind::Return
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::Unreachable => {}
-        }
-
-        self.check_for_move(trans, loc);
-    }
-
-    fn call_return_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _block: BasicBlock,
-        _func: &mir::Operand<'tcx>,
-        _args: &[mir::Operand<'tcx>],
-        return_place: mir::Place<'tcx>,
-    ) {
-        trans.gen(return_place.local);
-    }
-
-    fn yield_resume_effect(
-        &self,
-        trans: &mut impl GenKill<Self::Idx>,
-        _resume_block: BasicBlock,
-        resume_place: mir::Place<'tcx>,
-    ) {
-        trans.gen(resume_place.local);
-    }
-}
-
-impl<'mir, 'tcx> MaybeRequiresStorage<'mir, '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);
-    }
-}
-
-struct MoveVisitor<'a, 'mir, 'tcx, T> {
-    borrowed_locals: &'a RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
-    trans: &'a mut T,
-}
-
-impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, '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.trans.kill(*local);
-            }
-        }
-    }
-}