about summary refs log tree commit diff
path: root/compiler/rustc_mir_transform/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_transform/src')
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs6
-rw-r--r--compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs65
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs6
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs6
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coverage/tests.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs2
-rw-r--r--compiler/rustc_mir_transform/src/deduce_param_attrs.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs53
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs47
-rw-r--r--compiler/rustc_mir_transform/src/normalize_array_len.rs3
-rw-r--r--compiler/rustc_mir_transform/src/remove_false_edges.rs29
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs31
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs15
-rw-r--r--compiler/rustc_mir_transform/src/simplify_try.rs2
17 files changed, 145 insertions, 134 deletions
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index 9c22b5df73c..adf6ae4c727 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -490,10 +490,10 @@ fn check_unused_unsafe(
     unused_unsafes
 }
 
-fn unsafety_check_result<'tcx>(
-    tcx: TyCtxt<'tcx>,
+fn unsafety_check_result(
+    tcx: TyCtxt<'_>,
     def: ty::WithOptConstParam<LocalDefId>,
-) -> &'tcx UnsafetyCheckResult {
+) -> &UnsafetyCheckResult {
     debug!("unsafety_violations({:?})", def);
 
     // N.B., this borrow is valid because all the consumers of
diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
index 3378923c22c..d435d3ee69b 100644
--- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
+++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
@@ -1,39 +1,44 @@
-//! This module provides a pass to replacing the following statements with
-//! [`Nop`]s
+//! This module provides a pass that removes parts of MIR that are no longer relevant after
+//! analysis phase and borrowck. In particular, it removes false edges, user type annotations and
+//! replaces following statements with [`Nop`]s:
 //!
 //!   - [`AscribeUserType`]
 //!   - [`FakeRead`]
 //!   - [`Assign`] statements with a [`Shallow`] borrow
 //!
-//! The `CleanFakeReadsAndBorrows` "pass" is actually implemented as two
-//! traversals (aka visits) of the input MIR. The first traversal,
-//! `DeleteAndRecordFakeReads`, deletes the fake reads and finds the
-//! temporaries read by [`ForMatchGuard`] reads, and `DeleteFakeBorrows`
-//! deletes the initialization of those temporaries.
-//!
 //! [`AscribeUserType`]: rustc_middle::mir::StatementKind::AscribeUserType
-//! [`Shallow`]: rustc_middle::mir::BorrowKind::Shallow
-//! [`FakeRead`]: rustc_middle::mir::StatementKind::FakeRead
 //! [`Assign`]: rustc_middle::mir::StatementKind::Assign
-//! [`ForMatchGuard`]: rustc_middle::mir::FakeReadCause::ForMatchGuard
+//! [`FakeRead`]: rustc_middle::mir::StatementKind::FakeRead
 //! [`Nop`]: rustc_middle::mir::StatementKind::Nop
+//! [`Shallow`]: rustc_middle::mir::BorrowKind::Shallow
 
 use crate::MirPass;
-use rustc_middle::mir::visit::MutVisitor;
-use rustc_middle::mir::{Body, BorrowKind, Location, Rvalue};
-use rustc_middle::mir::{Statement, StatementKind};
+use rustc_middle::mir::{Body, BorrowKind, Rvalue, StatementKind, TerminatorKind};
 use rustc_middle::ty::TyCtxt;
 
-pub struct CleanupNonCodegenStatements;
+pub struct CleanupPostBorrowck;
 
-pub struct DeleteNonCodegenStatements<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
+impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
+    fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        for basic_block in body.basic_blocks.as_mut() {
+            for statement in basic_block.statements.iter_mut() {
+                match statement.kind {
+                    StatementKind::AscribeUserType(..)
+                    | StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
+                    | StatementKind::FakeRead(..) => statement.make_nop(),
+                    _ => (),
+                }
+            }
+            let terminator = basic_block.terminator_mut();
+            match terminator.kind {
+                TerminatorKind::FalseEdge { real_target, .. }
+                | TerminatorKind::FalseUnwind { real_target, .. } => {
+                    terminator.kind = TerminatorKind::Goto { target: real_target };
+                }
+                _ => {}
+            }
+        }
 
-impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let mut delete = DeleteNonCodegenStatements { tcx };
-        delete.visit_body_preserves_cfg(body);
         body.user_type_annotations.raw.clear();
 
         for decl in &mut body.local_decls {
@@ -41,19 +46,3 @@ impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
         }
     }
 }
-
-impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
-        match statement.kind {
-            StatementKind::AscribeUserType(..)
-            | StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
-            | StatementKind::FakeRead(..) => statement.make_nop(),
-            _ => (),
-        }
-        self.super_statement(statement, location);
-    }
-}
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index e384cfe1659..5c45abc5a17 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -655,11 +655,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             return None;
         }
 
-        if self.tcx.sess.mir_opt_level() >= 4 {
-            self.eval_rvalue_with_identities(rvalue, place)
-        } else {
-            self.use_ecx(|this| this.ecx.eval_rvalue_into_place(rvalue, place))
-        }
+        self.eval_rvalue_with_identities(rvalue, place)
     }
 
     // Attempt to use algebraic identities to eliminate constant expressions
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 782129be088..78d28f1ebab 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -282,9 +282,9 @@ impl graph::WithPredecessors for CoverageGraph {
 
 rustc_index::newtype_index! {
     /// A node in the control-flow graph of CoverageGraph.
+    #[debug_format = "bcb{}"]
     pub(super) struct BasicCoverageBlock {
-        DEBUG_FORMAT = "bcb{}",
-        const START_BCB = 0,
+        const START_BCB = 0;
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 60481014488..1468afc6456 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -533,10 +533,10 @@ fn make_code_region(
     }
 }
 
-fn fn_sig_and_body<'tcx>(
-    tcx: TyCtxt<'tcx>,
+fn fn_sig_and_body(
+    tcx: TyCtxt<'_>,
     def_id: DefId,
-) -> (Option<&'tcx rustc_hir::FnSig<'tcx>>, &'tcx rustc_hir::Body<'tcx>) {
+) -> (Option<&rustc_hir::FnSig<'_>>, &rustc_hir::Body<'_>) {
     // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back
     // to HIR for it.
     let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local");
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index dc1e68b253e..3bd7f31b45d 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -136,7 +136,7 @@ fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) ->
     coverage_visitor.info
 }
 
-fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> {
+fn covered_code_regions(tcx: TyCtxt<'_>, def_id: DefId) -> Vec<&CodeRegion> {
     let body = mir_body(tcx, def_id);
     body.basic_blocks
         .iter()
@@ -163,7 +163,7 @@ fn is_inlined(body: &Body<'_>, statement: &Statement<'_>) -> bool {
 /// This function ensures we obtain the correct MIR for the given item irrespective of
 /// whether that means const mir or runtime mir. For `const fn` this opts for runtime
 /// mir.
-fn mir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx mir::Body<'tcx> {
+fn mir_body(tcx: TyCtxt<'_>, def_id: DefId) -> &mir::Body<'_> {
     let id = ty::WithOptConstParam::unknown(def_id);
     let def = ty::InstanceDef::Item(id);
     tcx.instance_mir(def)
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index eba6a2b34e4..fa7f22303a8 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -169,7 +169,7 @@ impl<'tcx> MockBlocks<'tcx> {
     }
 }
 
-fn debug_basic_blocks<'tcx>(mir_body: &Body<'tcx>) -> String {
+fn debug_basic_blocks(mir_body: &Body<'_>) -> String {
     format!(
         "{:?}",
         mir_body
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index 42c580c63f0..09546330cec 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -71,7 +71,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
         bbs[block].statements[statement_index].make_nop();
     }
 
-    crate::simplify::SimplifyLocals.run_pass(tcx, body)
+    crate::simplify::simplify_locals(body, tcx)
 }
 
 pub struct DeadStoreElimination;
diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
index 92f1fff6beb..ddab7bbb2e3 100644
--- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
+++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
@@ -129,7 +129,7 @@ impl<'tcx> Visitor<'tcx> for DeduceReadOnly {
 }
 
 /// Returns true if values of a given type will never be passed indirectly, regardless of ABI.
-fn type_will_always_be_passed_directly<'tcx>(ty: Ty<'tcx>) -> bool {
+fn type_will_always_be_passed_directly(ty: Ty<'_>) -> bool {
     matches!(
         ty.kind(),
         ty::Bool
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 74d8337653f..08e296a8371 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -658,7 +658,7 @@ impl WriteInfo {
         }
     }
 
-    fn add_place<'tcx>(&mut self, place: Place<'tcx>) {
+    fn add_place(&mut self, place: Place<'_>) {
         self.writes.push(place.local);
     }
 
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 9d560f5c837..4219e6280eb 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -1,6 +1,7 @@
 //! Inlining pass for MIR functions
 use crate::deref_separator::deref_finder;
 use rustc_attr::InlineAttr;
+use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
@@ -27,6 +28,8 @@ const RESUME_PENALTY: usize = 45;
 
 const UNKNOWN_SIZE_COST: usize = 10;
 
+const TOP_DOWN_DEPTH_LIMIT: usize = 5;
+
 pub struct Inline;
 
 #[derive(Copy, Clone, Debug)]
@@ -86,8 +89,13 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
 
     let param_env = tcx.param_env_reveal_all_normalized(def_id);
 
-    let mut this =
-        Inliner { tcx, param_env, codegen_fn_attrs: tcx.codegen_fn_attrs(def_id), changed: false };
+    let mut this = Inliner {
+        tcx,
+        param_env,
+        codegen_fn_attrs: tcx.codegen_fn_attrs(def_id),
+        history: Vec::new(),
+        changed: false,
+    };
     let blocks = BasicBlock::new(0)..body.basic_blocks.next_index();
     this.process_blocks(body, blocks);
     this.changed
@@ -98,12 +106,26 @@ struct Inliner<'tcx> {
     param_env: ParamEnv<'tcx>,
     /// Caller codegen attributes.
     codegen_fn_attrs: &'tcx CodegenFnAttrs,
+    /// Stack of inlined instances.
+    /// We only check the `DefId` and not the substs because we want to
+    /// avoid inlining cases of polymorphic recursion.
+    /// The number of `DefId`s is finite, so checking history is enough
+    /// to ensure that we do not loop endlessly while inlining.
+    history: Vec<DefId>,
     /// Indicates that the caller body has been modified.
     changed: bool,
 }
 
 impl<'tcx> Inliner<'tcx> {
     fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range<BasicBlock>) {
+        // How many callsites in this body are we allowed to inline? We need to limit this in order
+        // to prevent super-linear growth in MIR size
+        let inline_limit = match self.history.len() {
+            0 => usize::MAX,
+            1..=TOP_DOWN_DEPTH_LIMIT => 1,
+            _ => return,
+        };
+        let mut inlined_count = 0;
         for bb in blocks {
             let bb_data = &caller_body[bb];
             if bb_data.is_cleanup {
@@ -122,12 +144,16 @@ impl<'tcx> Inliner<'tcx> {
                     debug!("not-inlined {} [{}]", callsite.callee, reason);
                     continue;
                 }
-                Ok(_) => {
+                Ok(new_blocks) => {
                     debug!("inlined {}", callsite.callee);
                     self.changed = true;
-                    // We could process the blocks returned by `try_inlining` here. However, that
-                    // leads to exponential compile times due to the top-down nature of this kind
-                    // of inlining.
+                    inlined_count += 1;
+                    if inlined_count == inline_limit {
+                        return;
+                    }
+                    self.history.push(callsite.callee.def_id());
+                    self.process_blocks(caller_body, new_blocks);
+                    self.history.pop();
                 }
             }
         }
@@ -289,7 +315,7 @@ impl<'tcx> Inliner<'tcx> {
     ) -> Option<CallSite<'tcx>> {
         // Only consider direct calls to functions
         let terminator = bb_data.terminator();
-        if let TerminatorKind::Call { ref func, target, .. } = terminator.kind {
+        if let TerminatorKind::Call { ref func, target, fn_span, .. } = terminator.kind {
             let func_ty = func.ty(caller_body, self.tcx);
             if let ty::FnDef(def_id, substs) = *func_ty.kind() {
                 // To resolve an instance its substs have to be fully normalized.
@@ -301,15 +327,14 @@ impl<'tcx> Inliner<'tcx> {
                     return None;
                 }
 
+                if self.history.contains(&callee.def_id()) {
+                    return None;
+                }
+
                 let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs);
+                let source_info = SourceInfo { span: fn_span, ..terminator.source_info };
 
-                return Some(CallSite {
-                    callee,
-                    fn_sig,
-                    block: bb,
-                    target,
-                    source_info: terminator.source_info,
-                });
+                return Some(CallSite { callee, fn_sig, block: bb, target, source_info });
             }
         }
 
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 93200b28830..16b8a901f36 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -77,8 +77,6 @@ mod match_branches;
 mod multiple_return_terminators;
 mod normalize_array_len;
 mod nrvo;
-// This pass is public to allow external drivers to perform MIR cleanup
-pub mod remove_false_edges;
 mod remove_noop_landing_pads;
 mod remove_storage_markers;
 mod remove_uninit_drops;
@@ -268,10 +266,7 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) ->
 /// Make MIR ready for const evaluation. This is run on all MIR, not just on consts!
 /// FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query).
 /// We used to have this for pre-miri MIR based const eval.
-fn mir_const<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def: ty::WithOptConstParam<LocalDefId>,
-) -> &'tcx Steal<Body<'tcx>> {
+fn mir_const(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &Steal<Body<'_>> {
     if let Some(def) = def.try_upgrade(tcx) {
         return tcx.mir_const(def);
     }
@@ -310,10 +305,10 @@ fn mir_const<'tcx>(
 }
 
 /// Compute the main MIR body and the list of MIR bodies of the promoteds.
-fn mir_promoted<'tcx>(
-    tcx: TyCtxt<'tcx>,
+fn mir_promoted(
+    tcx: TyCtxt<'_>,
     def: ty::WithOptConstParam<LocalDefId>,
-) -> (&'tcx Steal<Body<'tcx>>, &'tcx Steal<IndexVec<Promoted, Body<'tcx>>>) {
+) -> (&Steal<Body<'_>>, &Steal<IndexVec<Promoted, Body<'_>>>) {
     if let Some(def) = def.try_upgrade(tcx) {
         return tcx.mir_promoted(def);
     }
@@ -352,7 +347,7 @@ fn mir_promoted<'tcx>(
 }
 
 /// Compute the MIR that is used during CTFE (and thus has no optimizations run on it)
-fn mir_for_ctfe<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Body<'tcx> {
+fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> {
     let did = def_id.expect_local();
     if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
         tcx.mir_for_ctfe_of_const_arg(def)
@@ -366,10 +361,7 @@ fn mir_for_ctfe<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Body<'tcx> {
 /// we'd get cycle errors with `mir_for_ctfe`, because typeck would need to typeck
 /// the const parameter while type checking the main body, which in turn would try
 /// to type check the main body again.
-fn mir_for_ctfe_of_const_arg<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    (did, param_did): (LocalDefId, DefId),
-) -> &'tcx Body<'tcx> {
+fn mir_for_ctfe_of_const_arg(tcx: TyCtxt<'_>, (did, param_did): (LocalDefId, DefId)) -> &Body<'_> {
     tcx.arena.alloc(inner_mir_for_ctfe(
         tcx,
         ty::WithOptConstParam { did, const_param_did: Some(param_did) },
@@ -426,10 +418,10 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
 /// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs
 /// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't
 /// end up missing the source MIR due to stealing happening.
-fn mir_drops_elaborated_and_const_checked<'tcx>(
-    tcx: TyCtxt<'tcx>,
+fn mir_drops_elaborated_and_const_checked(
+    tcx: TyCtxt<'_>,
     def: ty::WithOptConstParam<LocalDefId>,
-) -> &'tcx Steal<Body<'tcx>> {
+) -> &Steal<Body<'_>> {
     if let Some(def) = def.try_upgrade(tcx) {
         return tcx.mir_drops_elaborated_and_const_checked(def);
     }
@@ -494,10 +486,9 @@ fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>
 /// After this series of passes, no lifetime analysis based on borrowing can be done.
 fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     let passes: &[&dyn MirPass<'tcx>] = &[
-        &remove_false_edges::RemoveFalseEdges,
+        &cleanup_post_borrowck::CleanupPostBorrowck,
         &simplify_branches::SimplifyConstCondition::new("initial"),
         &remove_noop_landing_pads::RemoveNoopLandingPads,
-        &cleanup_post_borrowck::CleanupNonCodegenStatements,
         &simplify::SimplifyCfg::new("early-opt"),
         &deref_separator::Derefer,
     ];
@@ -533,11 +524,8 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 
 /// Returns the sequence of passes that do the initial cleanup of runtime MIR.
 fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    let passes: &[&dyn MirPass<'tcx>] = &[
-        &elaborate_box_derefs::ElaborateBoxDerefs,
-        &lower_intrinsics::LowerIntrinsics,
-        &simplify::SimplifyCfg::new("elaborate-drops"),
-    ];
+    let passes: &[&dyn MirPass<'tcx>] =
+        &[&lower_intrinsics::LowerIntrinsics, &simplify::SimplifyCfg::new("elaborate-drops")];
 
     pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup)));
 }
@@ -569,6 +557,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             &multiple_return_terminators::MultipleReturnTerminators,
             &instcombine::InstCombine,
             &separate_const_switch::SeparateConstSwitch,
+            &simplify::SimplifyLocals::new("before-const-prop"),
             //
             // FIXME(#70073): This pass is responsible for both optimization as well as some lints.
             &const_prop::ConstProp,
@@ -587,7 +576,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             &o1(remove_noop_landing_pads::RemoveNoopLandingPads),
             &o1(simplify::SimplifyCfg::new("final")),
             &nrvo::RenameReturnPlace,
-            &simplify::SimplifyLocals,
+            &simplify::SimplifyLocals::new("final"),
             &multiple_return_terminators::MultipleReturnTerminators,
             &deduplicate_blocks::DeduplicateBlocks,
             // Some cleanup necessary at least for LLVM and potentially other codegen backends.
@@ -600,7 +589,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 }
 
 /// Optimize the MIR and prepare it for codegen.
-fn optimized_mir<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx Body<'tcx> {
+fn optimized_mir(tcx: TyCtxt<'_>, did: DefId) -> &Body<'_> {
     let did = did.expect_local();
     assert_eq!(ty::WithOptConstParam::try_lookup(did, tcx), None);
     tcx.arena.alloc(inner_optimized_mir(tcx, did))
@@ -637,10 +626,10 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
 
 /// Fetch all the promoteds of an item and prepare their MIR bodies to be ready for
 /// constant evaluation once all substitutions become known.
-fn promoted_mir<'tcx>(
-    tcx: TyCtxt<'tcx>,
+fn promoted_mir(
+    tcx: TyCtxt<'_>,
     def: ty::WithOptConstParam<LocalDefId>,
-) -> &'tcx IndexVec<Promoted, Body<'tcx>> {
+) -> &IndexVec<Promoted, Body<'_>> {
     if tcx.is_constructor(def.did.to_def_id()) {
         return tcx.arena.alloc(IndexVec::new());
     }
diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs
index a159e617178..1708b287e56 100644
--- a/compiler/rustc_mir_transform/src/normalize_array_len.rs
+++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs
@@ -16,7 +16,8 @@ pub struct NormalizeArrayLen;
 
 impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
-        sess.mir_opt_level() >= 4
+        // See #105929
+        sess.mir_opt_level() >= 4 && sess.opts.unstable_opts.unsound_mir_opts
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
diff --git a/compiler/rustc_mir_transform/src/remove_false_edges.rs b/compiler/rustc_mir_transform/src/remove_false_edges.rs
deleted file mode 100644
index 71f5ccf7e24..00000000000
--- a/compiler/rustc_mir_transform/src/remove_false_edges.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-use rustc_middle::mir::{Body, TerminatorKind};
-use rustc_middle::ty::TyCtxt;
-
-use crate::MirPass;
-
-/// Removes `FalseEdge` and `FalseUnwind` terminators from the MIR.
-///
-/// These are only needed for borrow checking, and can be removed afterwards.
-///
-/// FIXME: This should probably have its own MIR phase.
-pub struct RemoveFalseEdges;
-
-impl<'tcx> MirPass<'tcx> for RemoveFalseEdges {
-    fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        for block in body.basic_blocks_mut() {
-            let terminator = block.terminator_mut();
-            terminator.kind = match terminator.kind {
-                TerminatorKind::FalseEdge { real_target, .. } => {
-                    TerminatorKind::Goto { target: real_target }
-                }
-                TerminatorKind::FalseUnwind { real_target, .. } => {
-                    TerminatorKind::Goto { target: real_target }
-                }
-
-                _ => continue,
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index f8b55c86287..dace540fa29 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -174,9 +174,36 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
     let mut body =
         new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
 
+    // The first argument (index 0), but add 1 for the return value.
+    let mut dropee_ptr = Place::from(Local::new(1 + 0));
+    if tcx.sess.opts.unstable_opts.mir_emit_retag {
+        // We want to treat the function argument as if it was passed by `&mut`. As such, we
+        // generate
+        // ```
+        // temp = &mut *arg;
+        // Retag(temp, FnEntry)
+        // ```
+        // It's important that we do this first, before anything that depends on `dropee_ptr`
+        // has been put into the body.
+        let reborrow = Rvalue::Ref(
+            tcx.lifetimes.re_erased,
+            BorrowKind::Mut { allow_two_phase_borrow: false },
+            tcx.mk_place_deref(dropee_ptr),
+        );
+        let ref_ty = reborrow.ty(body.local_decls(), tcx);
+        dropee_ptr = body.local_decls.push(LocalDecl::new(ref_ty, span)).into();
+        let new_statements = [
+            StatementKind::Assign(Box::new((dropee_ptr, reborrow))),
+            StatementKind::Retag(RetagKind::FnEntry, Box::new(dropee_ptr)),
+        ];
+        for s in new_statements {
+            body.basic_blocks_mut()[START_BLOCK]
+                .statements
+                .push(Statement { source_info, kind: s });
+        }
+    }
+
     if ty.is_some() {
-        // The first argument (index 0), but add 1 for the return value.
-        let dropee_ptr = Place::from(Local::new(1 + 0));
         let patch = {
             let param_env = tcx.param_env_reveal_all_normalized(def_id);
             let mut elaborator =
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 8212a7b523b..8f6abe7a912 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -379,9 +379,21 @@ fn save_unreachable_coverage(
     ));
 }
 
-pub struct SimplifyLocals;
+pub struct SimplifyLocals {
+    label: String,
+}
+
+impl SimplifyLocals {
+    pub fn new(label: &str) -> SimplifyLocals {
+        SimplifyLocals { label: format!("SimplifyLocals-{}", label) }
+    }
+}
 
 impl<'tcx> MirPass<'tcx> for SimplifyLocals {
+    fn name(&self) -> &str {
+        &self.label
+    }
+
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() > 0
     }
@@ -557,6 +569,7 @@ fn remove_unused_definitions(used_locals: &mut UsedLocals, body: &mut Body<'_>)
 
                     StatementKind::SetDiscriminant { ref place, .. }
                     | StatementKind::Deinit(ref place) => used_locals.is_used(place.local),
+                    StatementKind::Nop => false,
                     _ => true,
                 };
 
diff --git a/compiler/rustc_mir_transform/src/simplify_try.rs b/compiler/rustc_mir_transform/src/simplify_try.rs
index baeb620ef24..e4f3ace9a93 100644
--- a/compiler/rustc_mir_transform/src/simplify_try.rs
+++ b/compiler/rustc_mir_transform/src/simplify_try.rs
@@ -532,7 +532,7 @@ struct VarField<'tcx> {
 }
 
 /// Match on `((_LOCAL as Variant).FIELD: TY)`.
-fn match_variant_field_place<'tcx>(place: Place<'tcx>) -> Option<(Local, VarField<'tcx>)> {
+fn match_variant_field_place(place: Place<'_>) -> Option<(Local, VarField<'_>)> {
     match place.as_ref() {
         PlaceRef {
             local,