about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-03-09 08:21:17 +0000
committerbors <bors@rust-lang.org>2023-03-09 08:21:17 +0000
commit39f2657d1101b50f9b71ae460b762d330cc8426b (patch)
treefa6be23bc0b0eed8b13d48d5200ad8c445ec69fa
parent66a2d6221069e0d08ceacf2a3201600e2092d2e0 (diff)
parenta22c5f9581cc0691be6838ee2a16ab4bd8af9a0b (diff)
downloadrust-39f2657d1101b50f9b71ae460b762d330cc8426b.tar.gz
rust-39f2657d1101b50f9b71ae460b762d330cc8426b.zip
Auto merge of #108920 - matthiaskrgr:rollup-qrr9a0u, r=matthiaskrgr
Rollup of 8 pull requests

Successful merges:

 - #108754 (Retry `pred_known_to_hold_modulo_regions` with fulfillment if ambiguous)
 - #108759 (1.41.1 supported 32-bit Apple targets)
 - #108839 (Canonicalize root var when making response from new solver)
 - #108856 (Remove DropAndReplace terminator)
 - #108882 (Tweak E0740)
 - #108898 (Set `LIBC_CHECK_CFG=1` when building Rust code in bootstrap)
 - #108911 (Improve rustdoc-gui/tester.js code a bit)
 - #108916 (Remove an unused return value in `rustc_hir_typeck`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--RELEASES.md4
-rw-r--r--compiler/rustc_borrowck/src/invalidation.rs9
-rw-r--r--compiler/rustc_borrowck/src/lib.rs10
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs3
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs19
-rw-r--r--compiler/rustc_borrowck/src/used_muts.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/analyze.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs6
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs3
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs3
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/resolver.rs15
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs12
-rw-r--r--compiler/rustc_hir_analysis/locales/en-US.ftl7
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs32
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs22
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs12
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs26
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs4
-rw-r--r--compiler/rustc_middle/src/mir/spanview.rs1
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs38
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs13
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs14
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs4
-rw-r--r--compiler/rustc_mir_build/src/lints.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs5
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs2
-rw-r--r--compiler/rustc_mir_transform/src/abort_unwinding_calls.rs2
-rw-r--r--compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs3
-rw-r--r--compiler/rustc_mir_transform/src/add_retag.rs2
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs1
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs1
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs1
-rw-r--r--compiler/rustc_mir_transform/src/coverage/debug.rs1
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs1
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs1
-rw-r--r--compiler/rustc_mir_transform/src/coverage/tests.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs3
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs119
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs2
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs10
-rw-r--r--compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs1
-rw-r--r--compiler/rustc_mir_transform/src/remove_uninit_drops.rs23
-rw-r--r--compiler/rustc_mir_transform/src/separate_const_switch.rs2
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs43
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs8
-rw-r--r--library/core/src/intrinsics/mir.rs3
-rw-r--r--src/bootstrap/builder.rs9
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs4
-rw-r--r--src/tools/rustdoc-gui/tester.js48
-rw-r--r--tests/mir-opt/building/custom/terminators.drop_first.built.after.mir5
-rw-r--r--tests/mir-opt/building/custom/terminators.rs3
-rw-r--r--tests/ui/traits/new-solver/canonical-ty-var-eq-in-response.rs39
-rw-r--r--tests/ui/traits/new-solver/deduce-ty-from-object.rs6
-rw-r--r--tests/ui/union/field_checks.rs10
-rw-r--r--tests/ui/union/field_checks.stderr30
-rw-r--r--tests/ui/union/issue-41073.rs2
-rw-r--r--tests/ui/union/issue-41073.stderr6
-rw-r--r--tests/ui/union/union-with-drop-fields.mirunsafeck.stderr18
-rw-r--r--tests/ui/union/union-with-drop-fields.rs6
-rw-r--r--tests/ui/union/union-with-drop-fields.thirunsafeck.stderr18
-rw-r--r--tests/ui/union/unresolved-field-isnt-copy.rs8
-rw-r--r--tests/ui/union/unresolved-field-isnt-copy.stderr9
71 files changed, 284 insertions, 461 deletions
diff --git a/RELEASES.md b/RELEASES.md
index f418ab23d10..4e974bbe974 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -3861,6 +3861,8 @@ Version 1.41.1 (2020-02-27)
 * [Always check types of static items][69145]
 * [Always check lifetime bounds of `Copy` impls][69145]
 * [Fix miscompilation in callers of `Layout::repeat`][69225]
+* [Rust 1.41.0 was announced as the last Rust release with tier 1 or tier 2 support for 32-bit Apple targets][apple-32bit-drop].
+  That announcement did not expect a patch release. 1.41.1 also includes release binaries for these targets.
 
 [69225]: https://github.com/rust-lang/rust/issues/69225
 [69145]: https://github.com/rust-lang/rust/pull/69145
@@ -3953,7 +3955,7 @@ Misc
 Compatibility Notes
 -------------------
 
-- [As previously announced 1.41.0 will be the last tier 1 release for 32-bit
+- [As previously announced 1.41 will be the last tier 1 release for 32-bit
   Apple targets.][apple-32bit-drop] This means that the source code is still
   available to build, but the targets are no longer being tested and release
   binaries for those platforms will no longer be distributed by the Rust project.
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index 6217676d5c1..1006a047cce 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -118,15 +118,6 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
                     LocalMutationIsAllowed::Yes,
                 );
             }
-            TerminatorKind::DropAndReplace {
-                place: drop_place,
-                value: new_value,
-                target: _,
-                unwind: _,
-            } => {
-                self.mutate_place(location, *drop_place, Deep);
-                self.consume_operand(location, new_value);
-            }
             TerminatorKind::Call {
                 func,
                 args,
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 0fc3240c560..92acd755509 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -743,15 +743,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
                     flow_state,
                 );
             }
-            TerminatorKind::DropAndReplace {
-                place: drop_place,
-                value: new_value,
-                target: _,
-                unwind: _,
-            } => {
-                self.mutate_place(loc, (*drop_place, span), Deep, flow_state);
-                self.consume_operand(loc, (new_value, span), flow_state);
-            }
             TerminatorKind::Call {
                 func,
                 args,
@@ -866,7 +857,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
             | TerminatorKind::Assert { .. }
             | TerminatorKind::Call { .. }
             | TerminatorKind::Drop { .. }
-            | TerminatorKind::DropAndReplace { .. }
             | TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
             | TerminatorKind::FalseUnwind { real_target: _, unwind: _ }
             | TerminatorKind::Goto { .. }
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index a687d3f5352..9731b10aa99 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -435,8 +435,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
         //
         // What we *actually* generate is a store to a temporary
         // for the call (`TMP = call()...`) and then a
-        // `DropAndReplace` to swap that with `X`
-        // (`DropAndReplace` has very particular semantics).
+        // `Drop(X)` followed by `X = TMP`  to swap that with `X`.
     }
 }
 
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 06c7b8b8f87..d85e058bb20 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1312,24 +1312,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 // no checks needed for these
             }
 
-            TerminatorKind::DropAndReplace { place, value, target: _, unwind: _ } => {
-                let place_ty = place.ty(body, tcx).ty;
-                let rv_ty = value.ty(body, tcx);
-
-                let locations = term_location.to_locations();
-                if let Err(terr) =
-                    self.sub_types(rv_ty, place_ty, locations, ConstraintCategory::Assignment)
-                {
-                    span_mirbug!(
-                        self,
-                        term,
-                        "bad DropAndReplace ({:?} = {:?}): {:?}",
-                        place_ty,
-                        rv_ty,
-                        terr
-                    );
-                }
-            }
             TerminatorKind::SwitchInt { discr, .. } => {
                 self.check_operand(discr, term_location);
 
@@ -1629,7 +1611,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             }
             TerminatorKind::Unreachable => {}
             TerminatorKind::Drop { target, unwind, .. }
-            | TerminatorKind::DropAndReplace { target, unwind, .. }
             | TerminatorKind::Assert { target, cleanup: unwind, .. } => {
                 self.assert_iscleanup(body, block_data, target, is_cleanup);
                 if let Some(unwind) = unwind {
diff --git a/compiler/rustc_borrowck/src/used_muts.rs b/compiler/rustc_borrowck/src/used_muts.rs
index 18dbe24d3b8..c5991e0bc25 100644
--- a/compiler/rustc_borrowck/src/used_muts.rs
+++ b/compiler/rustc_borrowck/src/used_muts.rs
@@ -71,9 +71,6 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc
             TerminatorKind::Call { destination, .. } => {
                 self.remove_never_initialized_mut_locals(*destination);
             }
-            TerminatorKind::DropAndReplace { place, .. } => {
-                self.remove_never_initialized_mut_locals(*place);
-            }
             _ => {}
         }
 
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 7f857528c7c..cb0e272ceda 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -499,7 +499,6 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
             TerminatorKind::Yield { .. }
             | TerminatorKind::FalseEdge { .. }
             | TerminatorKind::FalseUnwind { .. }
-            | TerminatorKind::DropAndReplace { .. }
             | TerminatorKind::GeneratorDrop => {
                 bug!("shouldn't exist at codegen {:?}", bb_data.terminator());
             }
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 49c4f1aaaef..1930db72ead 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -543,8 +543,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
                     | TerminatorKind::Unreachable
                     | TerminatorKind::Drop { .. }
                     | TerminatorKind::Assert { .. } => {}
-                    TerminatorKind::DropAndReplace { .. }
-                    | TerminatorKind::Yield { .. }
+                    TerminatorKind::Yield { .. }
                     | TerminatorKind::GeneratorDrop
                     | TerminatorKind::FalseEdge { .. }
                     | TerminatorKind::FalseUnwind { .. } => unreachable!(),
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index 95aad10fdb0..0ce395e912d 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -295,7 +295,6 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
                 TerminatorKind::Call { cleanup: unwind, .. }
                 | TerminatorKind::InlineAsm { cleanup: unwind, .. }
                 | TerminatorKind::Assert { cleanup: unwind, .. }
-                | TerminatorKind::DropAndReplace { unwind, .. }
                 | TerminatorKind::Drop { unwind, .. } => {
                     if let Some(unwind) = unwind {
                         debug!(
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 57a19a4ab1e..71c71d59b7a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1305,10 +1305,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     mergeable_succ(),
                 ),
 
-            mir::TerminatorKind::DropAndReplace { .. } => {
-                bug!("undesugared DropAndReplace in codegen: {:?}", terminator);
-            }
-
             mir::TerminatorKind::Call {
                 ref func,
                 ref args,
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 2aea7c79b6d..685a5599cde 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -171,11 +171,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             Unreachable => throw_ub!(Unreachable),
 
             // These should never occur for MIR we actually run.
-            DropAndReplace { .. }
-            | FalseEdge { .. }
-            | FalseUnwind { .. }
-            | Yield { .. }
-            | GeneratorDrop => span_bug!(
+            FalseEdge { .. } | FalseUnwind { .. } | Yield { .. } | GeneratorDrop => span_bug!(
                 terminator.source_info.span,
                 "{:#?} should have been eliminated by MIR pass",
                 terminator.kind
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index cc3aa84bd71..656baa784d7 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -985,8 +985,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
 
             // Forbid all `Drop` terminators unless the place being dropped is a local with no
             // projections that cannot be `NeedsNonConstDrop`.
-            TerminatorKind::Drop { place: dropped_place, .. }
-            | TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
+            TerminatorKind::Drop { place: dropped_place, .. } => {
                 // If we are checking live drops after drop-elaboration, don't emit duplicate
                 // errors here.
                 if super::post_drop_elaboration::checking_enabled(self.ccx) {
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
index cf4e875c91f..43806035a44 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
@@ -80,8 +80,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
         trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
 
         match &terminator.kind {
-            mir::TerminatorKind::Drop { place: dropped_place, .. }
-            | mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
+            mir::TerminatorKind::Drop { place: dropped_place, .. } => {
                 let dropped_ty = dropped_place.ty(self.body, self.tcx).ty;
                 if !NeedsNonConstDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
                     // Instead of throwing a bug, we just return here. This is because we have to
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index 805e6096b35..78c74e1892d 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -222,23 +222,8 @@ where
         // The effect of assignment to the return place in `TerminatorKind::Call` is not applied
         // here; that occurs in `apply_call_return_effect`.
 
-        if let mir::TerminatorKind::DropAndReplace { value, place, .. } = &terminator.kind {
-            let qualif = qualifs::in_operand::<Q, _>(
-                self.ccx,
-                &mut |l| self.state.qualif.contains(l),
-                value,
-            );
-
-            if !place.is_indirect() {
-                self.assign_qualif_direct(place, qualif);
-            }
-        }
-
         // We ignore borrow on drop because custom drop impls are not allowed in consts.
         // FIXME: Reconsider if accounting for borrows in drops is necessary for const drop.
-
-        // We need to assign qualifs to the dropped location before visiting the operand that
-        // replaces it since qualifs can be cleared on move.
         self.super_terminator(terminator, location);
     }
 }
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 272fe3d1b31..8ecd8f639dd 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -846,18 +846,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     self.check_edge(location, *unwind, EdgeKind::Unwind);
                 }
             }
-            TerminatorKind::DropAndReplace { target, unwind, .. } => {
-                if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
-                    self.fail(
-                        location,
-                        "`DropAndReplace` should have been removed during drop elaboration",
-                    );
-                }
-                self.check_edge(location, *target, EdgeKind::Normal);
-                if let Some(unwind) = unwind {
-                    self.check_edge(location, *unwind, EdgeKind::Unwind);
-                }
-            }
             TerminatorKind::Call { func, args, destination, target, cleanup, .. } => {
                 let func_ty = func.ty(&self.body.local_decls, self.tcx);
                 match func_ty.kind() {
diff --git a/compiler/rustc_hir_analysis/locales/en-US.ftl b/compiler/rustc_hir_analysis/locales/en-US.ftl
index 3c62529442c..df428816444 100644
--- a/compiler/rustc_hir_analysis/locales/en-US.ftl
+++ b/compiler/rustc_hir_analysis/locales/en-US.ftl
@@ -163,3 +163,10 @@ hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function
     .help = cast the value to `{$cast_ty}`
 
 hir_analysis_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}`
+
+hir_analysis_invalid_union_field =
+    field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
+    .note = union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+
+hir_analysis_invalid_union_field_sugg =
+    wrap the field type in `ManuallyDrop<...>`
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 3449d3d439d..be0ae4ce2ef 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1,5 +1,5 @@
 use crate::check::intrinsicck::InlineAsmCtxt;
-use crate::errors::LinkageType;
+use crate::errors::{self, LinkageType};
 
 use super::compare_impl_item::check_type_bounds;
 use super::compare_impl_item::{compare_impl_method, compare_impl_ty};
@@ -114,9 +114,11 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
                     allowed_union_field(*elem, tcx, param_env)
                 }
                 _ => {
-                    // Fallback case: allow `ManuallyDrop` and things that are `Copy`.
+                    // Fallback case: allow `ManuallyDrop` and things that are `Copy`,
+                    // also no need to report an error if the type is unresolved.
                     ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop())
                         || ty.is_copy_modulo_regions(tcx, param_env)
+                        || ty.references_error()
                 }
             }
         }
@@ -131,26 +133,14 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
                     Some(Node::Field(field)) => (field.span, field.ty.span),
                     _ => unreachable!("mir field has to correspond to hir field"),
                 };
-                struct_span_err!(
-                    tcx.sess,
+                tcx.sess.emit_err(errors::InvalidUnionField {
                     field_span,
-                    E0740,
-                    "unions cannot contain fields that may need dropping"
-                )
-                .note(
-                    "a type is guaranteed not to need dropping \
-                    when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type",
-                )
-                .multipart_suggestion_verbose(
-                    "when the type does not implement `Copy`, \
-                    wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped",
-                    vec![
-                        (ty_span.shrink_to_lo(), "std::mem::ManuallyDrop<".into()),
-                        (ty_span.shrink_to_hi(), ">".into()),
-                    ],
-                    Applicability::MaybeIncorrect,
-                )
-                .emit();
+                    sugg: errors::InvalidUnionFieldSuggestion {
+                        lo: ty_span.shrink_to_lo(),
+                        hi: ty_span.shrink_to_hi(),
+                    },
+                    note: (),
+                });
                 return false;
             } else if field_ty.needs_drop(tcx, param_env) {
                 // This should never happen. But we can get here e.g. in case of name resolution errors.
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 74fec93d91e..dd40706f1d3 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -5,7 +5,7 @@ use rustc_errors::{
     error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
     MultiSpan,
 };
-use rustc_macros::Diagnostic;
+use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_middle::ty::Ty;
 use rustc_span::{symbol::Ident, Span, Symbol};
 
@@ -430,3 +430,23 @@ pub(crate) struct CastThinPointerToFatPointer<'tcx> {
     pub expr_ty: Ty<'tcx>,
     pub cast_ty: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_invalid_union_field, code = "E0740")]
+pub(crate) struct InvalidUnionField {
+    #[primary_span]
+    pub field_span: Span,
+    #[subdiagnostic]
+    pub sugg: InvalidUnionFieldSuggestion,
+    #[note]
+    pub note: (),
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(hir_analysis_invalid_union_field_sugg, applicability = "machine-applicable")]
+pub(crate) struct InvalidUnionFieldSuggestion {
+    #[suggestion_part(code = "std::mem::ManuallyDrop<")]
+    pub lo: Span,
+    #[suggestion_part(code = ">")]
+    pub hi: Span,
+}
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index a8f8121153f..ac7d984c161 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -301,16 +301,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
         def_id: DefId,
         substs: SubstsRef<'tcx>,
-    ) -> (ty::InstantiatedPredicates<'tcx>, Vec<Span>) {
+    ) -> ty::InstantiatedPredicates<'tcx> {
         let bounds = self.tcx.predicates_of(def_id);
-        let spans: Vec<Span> = bounds.predicates.iter().map(|(_, span)| *span).collect();
         let result = bounds.instantiate(self.tcx, substs);
         let result = self.normalize(span, result);
-        debug!(
-            "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}",
-            bounds, substs, result, spans,
-        );
-        (result, spans)
+        debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}", bounds, substs, result);
+        result
     }
 
     pub(in super::super) fn normalize<T>(&self, span: Span, value: T) -> T
@@ -1389,7 +1385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             _ => false,
         };
-        let (bounds, _) = self.instantiate_bounds(span, def_id, &substs);
+        let bounds = self.instantiate_bounds(span, def_id, &substs);
 
         for mut obligation in traits::predicates_for_generics(
             |idx, predicate_span| {
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 001b24c31de..a43330e2d4e 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -374,9 +374,18 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
         }
     }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, mut t: Ty<'tcx>) -> Ty<'tcx> {
         match *t.kind() {
-            ty::Infer(ty::TyVar(vid)) => {
+            ty::Infer(ty::TyVar(mut vid)) => {
+                // We need to canonicalize the *root* of our ty var.
+                // This is so that our canonical response correctly reflects
+                // any equated inference vars correctly!
+                let root_vid = self.infcx.root_var(vid);
+                if root_vid != vid {
+                    t = self.infcx.tcx.mk_ty_var(root_vid);
+                    vid = root_vid;
+                }
+
                 debug!("canonical: type var found with vid {:?}", vid);
                 match self.infcx.probe_ty_var(vid) {
                     // `t` could be a float / int variable; canonicalize that instead.
@@ -467,9 +476,18 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
         }
     }
 
-    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+    fn fold_const(&mut self, mut ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
         match ct.kind() {
-            ty::ConstKind::Infer(InferConst::Var(vid)) => {
+            ty::ConstKind::Infer(InferConst::Var(mut vid)) => {
+                // We need to canonicalize the *root* of our const var.
+                // This is so that our canonical response correctly reflects
+                // any equated inference vars correctly!
+                let root_vid = self.infcx.root_const_var(vid);
+                if root_vid != vid {
+                    ct = self.infcx.tcx.mk_const(ty::InferConst::Var(root_vid), ct.ty());
+                    vid = root_vid;
+                }
+
                 debug!("canonical: const var found with vid {:?}", vid);
                 match self.infcx.probe_const_var(vid) {
                     Ok(c) => {
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index fb067e7ac21..4a2a5557313 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1359,6 +1359,10 @@ impl<'tcx> InferCtxt<'tcx> {
         self.inner.borrow_mut().type_variables().root_var(var)
     }
 
+    pub fn root_const_var(&self, var: ty::ConstVid<'tcx>) -> ty::ConstVid<'tcx> {
+        self.inner.borrow_mut().const_unification_table().find(var)
+    }
+
     /// Where possible, replaces type/const variables in
     /// `value` with their final value. Note that region variables
     /// are unaffected. If a type/const variable has not been unified, it
diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs
index 28a3b51b7fc..e52610faf5a 100644
--- a/compiler/rustc_middle/src/mir/spanview.rs
+++ b/compiler/rustc_middle/src/mir/spanview.rs
@@ -265,7 +265,6 @@ pub fn terminator_kind_name(term: &Terminator<'_>) -> &'static str {
         Return => "Return",
         Unreachable => "Unreachable",
         Drop { .. } => "Drop",
-        DropAndReplace { .. } => "DropAndReplace",
         Call { .. } => "Call",
         Assert { .. } => "Assert",
         Yield { .. } => "Yield",
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index ae09562a85e..58c060db660 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -133,7 +133,6 @@ pub enum AnalysisPhase {
 pub enum RuntimePhase {
     /// In addition to the semantic changes, beginning with this phase, the following variants are
     /// disallowed:
-    /// * [`TerminatorKind::DropAndReplace`]
     /// * [`TerminatorKind::Yield`]
     /// * [`TerminatorKind::GeneratorDrop`]
     /// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
@@ -596,43 +595,6 @@ pub enum TerminatorKind<'tcx> {
     /// > consider indirect assignments.
     Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
 
-    /// Drops the place and assigns a new value to it.
-    ///
-    /// This first performs the exact same operation as the pre drop-elaboration `Drop` terminator;
-    /// it then additionally assigns the `value` to the `place` as if by an assignment statement.
-    /// This assignment occurs both in the unwind and the regular code paths. The semantics are best
-    /// explained by the elaboration:
-    ///
-    /// ```ignore (MIR)
-    /// BB0 {
-    ///   DropAndReplace(P <- V, goto BB1, unwind BB2)
-    /// }
-    /// ```
-    ///
-    /// becomes
-    ///
-    /// ```ignore (MIR)
-    /// BB0 {
-    ///   Drop(P, goto BB1, unwind BB2)
-    /// }
-    /// BB1 {
-    ///   // P is now uninitialized
-    ///   P <- V
-    /// }
-    /// BB2 {
-    ///   // P is now uninitialized -- its dtor panicked
-    ///   P <- V
-    /// }
-    /// ```
-    ///
-    /// Disallowed after drop elaboration.
-    DropAndReplace {
-        place: Place<'tcx>,
-        value: Operand<'tcx>,
-        target: BasicBlock,
-        unwind: Option<BasicBlock>,
-    },
-
     /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
     /// the referred to function. The operand types must match the argument types of the function.
     /// The return place type must match the return type. The type of the `func` operand must be
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 6e905224c13..cd970270727 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -148,7 +148,6 @@ impl<'tcx> TerminatorKind<'tcx> {
             | Call { target: None, cleanup: Some(t), .. }
             | Call { target: Some(t), cleanup: None, .. }
             | Yield { resume: t, drop: None, .. }
-            | DropAndReplace { target: t, unwind: None, .. }
             | Drop { target: t, unwind: None, .. }
             | Assert { target: t, cleanup: None, .. }
             | FalseUnwind { real_target: t, unwind: None }
@@ -158,7 +157,6 @@ impl<'tcx> TerminatorKind<'tcx> {
             }
             Call { target: Some(t), cleanup: Some(ref u), .. }
             | Yield { resume: t, drop: Some(ref u), .. }
-            | DropAndReplace { target: t, unwind: Some(ref u), .. }
             | Drop { target: t, unwind: Some(ref u), .. }
             | Assert { target: t, cleanup: Some(ref u), .. }
             | FalseUnwind { real_target: t, unwind: Some(ref u) }
@@ -188,7 +186,6 @@ impl<'tcx> TerminatorKind<'tcx> {
             | Call { target: None, cleanup: Some(ref mut t), .. }
             | Call { target: Some(ref mut t), cleanup: None, .. }
             | Yield { resume: ref mut t, drop: None, .. }
-            | DropAndReplace { target: ref mut t, unwind: None, .. }
             | Drop { target: ref mut t, unwind: None, .. }
             | Assert { target: ref mut t, cleanup: None, .. }
             | FalseUnwind { real_target: ref mut t, unwind: None }
@@ -198,7 +195,6 @@ impl<'tcx> TerminatorKind<'tcx> {
             }
             Call { target: Some(ref mut t), cleanup: Some(ref mut u), .. }
             | Yield { resume: ref mut t, drop: Some(ref mut u), .. }
-            | DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. }
             | Drop { target: ref mut t, unwind: Some(ref mut u), .. }
             | Assert { target: ref mut t, cleanup: Some(ref mut u), .. }
             | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) }
@@ -225,7 +221,6 @@ impl<'tcx> TerminatorKind<'tcx> {
             | TerminatorKind::FalseEdge { .. } => None,
             TerminatorKind::Call { cleanup: ref unwind, .. }
             | TerminatorKind::Assert { cleanup: ref unwind, .. }
-            | TerminatorKind::DropAndReplace { ref unwind, .. }
             | TerminatorKind::Drop { ref unwind, .. }
             | TerminatorKind::FalseUnwind { ref unwind, .. }
             | TerminatorKind::InlineAsm { cleanup: ref unwind, .. } => Some(unwind),
@@ -245,7 +240,6 @@ impl<'tcx> TerminatorKind<'tcx> {
             | TerminatorKind::FalseEdge { .. } => None,
             TerminatorKind::Call { cleanup: ref mut unwind, .. }
             | TerminatorKind::Assert { cleanup: ref mut unwind, .. }
-            | TerminatorKind::DropAndReplace { ref mut unwind, .. }
             | TerminatorKind::Drop { ref mut unwind, .. }
             | TerminatorKind::FalseUnwind { ref mut unwind, .. }
             | TerminatorKind::InlineAsm { cleanup: ref mut unwind, .. } => Some(unwind),
@@ -309,9 +303,6 @@ impl<'tcx> TerminatorKind<'tcx> {
             Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value),
             Unreachable => write!(fmt, "unreachable"),
             Drop { place, .. } => write!(fmt, "drop({:?})", place),
-            DropAndReplace { place, value, .. } => {
-                write!(fmt, "replace({:?} <- {:?})", place, value)
-            }
             Call { func, args, destination, .. } => {
                 write!(fmt, "{:?} = ", destination)?;
                 write!(fmt, "{:?}(", func)?;
@@ -403,10 +394,10 @@ impl<'tcx> TerminatorKind<'tcx> {
             Call { target: None, cleanup: None, .. } => vec![],
             Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()],
             Yield { drop: None, .. } => vec!["resume".into()],
-            DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => {
+            Drop { unwind: None, .. } => {
                 vec!["return".into()]
             }
-            DropAndReplace { unwind: Some(_), .. } | Drop { unwind: Some(_), .. } => {
+            Drop { unwind: Some(_), .. } => {
                 vec!["return".into(), "unwind".into()]
             }
             Assert { cleanup: None, .. } => vec!["".into()],
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 5c056b29975..14b18618aa8 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -495,20 +495,6 @@ macro_rules! make_mir_visitor {
                         );
                     }
 
-                    TerminatorKind::DropAndReplace {
-                        place,
-                        value,
-                        target: _,
-                        unwind: _,
-                    } => {
-                        self.visit_place(
-                            place,
-                            PlaceContext::MutatingUse(MutatingUseContext::Drop),
-                            location
-                        );
-                        self.visit_operand(value, location);
-                    }
-
                     TerminatorKind::Call {
                         func,
                         args,
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index 09d2eb96d0f..5e77f2dc126 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -59,14 +59,6 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
                     unwind: None,
                 })
             },
-            @call("mir_drop_and_replace", args) => {
-                Ok(TerminatorKind::DropAndReplace {
-                    place: self.parse_place(args[0])?,
-                    value: self.parse_operand(args[1])?,
-                    target: self.parse_block(args[2])?,
-                    unwind: None,
-                })
-            },
             @call("mir_call", args) => {
                 let destination = self.parse_place(args[0])?;
                 let target = self.parse_block(args[1])?;
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 770701b3750..4bc2c0ca791 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -1072,7 +1072,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 TerminatorKind::Assert { .. }
                     | TerminatorKind::Call { .. }
                     | TerminatorKind::Drop { .. }
-                    | TerminatorKind::DropAndReplace { .. }
                     | TerminatorKind::FalseUnwind { .. }
                     | TerminatorKind::InlineAsm { .. }
             ),
@@ -1432,8 +1431,7 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
                     *unwind = Some(to);
                 }
             }
-            TerminatorKind::DropAndReplace { unwind, .. }
-            | TerminatorKind::FalseUnwind { unwind, .. }
+            TerminatorKind::FalseUnwind { unwind, .. }
             | TerminatorKind::Call { cleanup: unwind, .. }
             | TerminatorKind::Assert { cleanup: unwind, .. }
             | TerminatorKind::InlineAsm { cleanup: unwind, .. } => {
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index f67f24b43c4..f6db329fd7c 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -128,7 +128,6 @@ impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
             TerminatorKind::Assert { .. }
             | TerminatorKind::Call { .. }
             | TerminatorKind::Drop { .. }
-            | TerminatorKind::DropAndReplace { .. }
             | TerminatorKind::FalseEdge { .. }
             | TerminatorKind::FalseUnwind { .. }
             | TerminatorKind::Goto { .. }
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index 2ae3ae02fcc..a40c38aa4c3 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -480,7 +480,6 @@ impl Direction for Forward {
 
             Assert { target, cleanup: unwind, expected: _, msg: _, cond: _ }
             | Drop { target, unwind, place: _ }
-            | DropAndReplace { target, unwind, value: _, place: _ }
             | FalseUnwind { real_target: target, unwind } => {
                 if let Some(unwind) = unwind {
                     propagate(unwind, exit_state);
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index 6f4e7fd4682..08fadfe68a1 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -111,8 +111,7 @@ where
         self.super_terminator(terminator, location);
 
         match terminator.kind {
-            mir::TerminatorKind::Drop { place: dropped_place, .. }
-            | mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
+            mir::TerminatorKind::Drop { place: dropped_place, .. } => {
                 // 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
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index fcf0ce9d821..60fd5169054 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -202,7 +202,6 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
             TerminatorKind::Abort
             | TerminatorKind::Assert { .. }
             | TerminatorKind::Drop { .. }
-            | TerminatorKind::DropAndReplace { .. }
             | TerminatorKind::FalseEdge { .. }
             | TerminatorKind::FalseUnwind { .. }
             | TerminatorKind::GeneratorDrop
@@ -240,7 +239,6 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
             | TerminatorKind::Abort
             | TerminatorKind::Assert { .. }
             | TerminatorKind::Drop { .. }
-            | TerminatorKind::DropAndReplace { .. }
             | TerminatorKind::FalseEdge { .. }
             | TerminatorKind::FalseUnwind { .. }
             | TerminatorKind::GeneratorDrop
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 4a163028fcf..fa62960eee0 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -392,11 +392,6 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
                 self.create_move_path(place);
                 self.gather_init(place.as_ref(), InitKind::Deep);
             }
-            TerminatorKind::DropAndReplace { place, ref value, .. } => {
-                self.create_move_path(place);
-                self.gather_operand(value);
-                self.gather_init(place.as_ref(), InitKind::Deep);
-            }
             TerminatorKind::Call {
                 ref func,
                 ref args,
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 34c60b5ff3c..b1474a770c5 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -230,7 +230,7 @@ pub trait ValueAnalysis<'tcx> {
             TerminatorKind::Drop { place, .. } => {
                 state.flood_with(place.as_ref(), self.map(), Self::Value::bottom());
             }
-            TerminatorKind::DropAndReplace { .. } | TerminatorKind::Yield { .. } => {
+            TerminatorKind::Yield { .. } => {
                 // They would have an effect, but are not allowed in this phase.
                 bug!("encountered disallowed terminator");
             }
diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
index 9b4b720702b..893018e0d8e 100644
--- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
+++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
@@ -74,7 +74,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
                     };
                     layout::fn_can_unwind(tcx, fn_def_id, sig.abi())
                 }
-                TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => {
+                TerminatorKind::Drop { .. } => {
                     tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Unwind
                         && layout::fn_can_unwind(tcx, None, Abi::Rust)
                 }
diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
index 9b2260f6825..896fcd9cdd6 100644
--- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
+++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
@@ -64,9 +64,6 @@ fn add_moves_for_packed_drops_patch<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>)
             {
                 add_move_for_packed_drop(tcx, body, &mut patch, terminator, loc, data.is_cleanup);
             }
-            TerminatorKind::DropAndReplace { .. } => {
-                span_bug!(terminator.source_info.span, "replace in AddMovesForPackedDrops");
-            }
             _ => {}
         }
     }
diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs
index 7d2146214c6..916f2904dda 100644
--- a/compiler/rustc_mir_transform/src/add_retag.rs
+++ b/compiler/rustc_mir_transform/src/add_retag.rs
@@ -100,7 +100,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
                     }
 
                     // `Drop` is also a call, but it doesn't return anything so we are good.
-                    TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => None,
+                    TerminatorKind::Drop { .. } => None,
                     // Not a block ending in a Call -> ignore.
                     _ => None,
                 }
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index 71605113dd5..c61947c566d 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -55,7 +55,6 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
             | TerminatorKind::Drop { .. }
             | TerminatorKind::Yield { .. }
             | TerminatorKind::Assert { .. }
-            | TerminatorKind::DropAndReplace { .. }
             | TerminatorKind::GeneratorDrop
             | TerminatorKind::Resume
             | TerminatorKind::Abort
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 6b2eefce24d..9bc4b26db92 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -1007,7 +1007,6 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
             | TerminatorKind::Return
             | TerminatorKind::Unreachable
             | TerminatorKind::Drop { .. }
-            | TerminatorKind::DropAndReplace { .. }
             | TerminatorKind::Yield { .. }
             | TerminatorKind::GeneratorDrop
             | TerminatorKind::FalseEdge { .. }
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 6c1980ff3ad..77402b8737e 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -686,7 +686,6 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
             | TerminatorKind::Return
             | TerminatorKind::Unreachable
             | TerminatorKind::Drop { .. }
-            | TerminatorKind::DropAndReplace { .. }
             | TerminatorKind::Yield { .. }
             | TerminatorKind::GeneratorDrop
             | TerminatorKind::FalseEdge { .. }
diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs
index 22ea8710e6a..0e7dc171a5d 100644
--- a/compiler/rustc_mir_transform/src/coverage/debug.rs
+++ b/compiler/rustc_mir_transform/src/coverage/debug.rs
@@ -822,7 +822,6 @@ pub(super) fn term_type(kind: &TerminatorKind<'_>) -> &'static str {
         TerminatorKind::Return => "Return",
         TerminatorKind::Unreachable => "Unreachable",
         TerminatorKind::Drop { .. } => "Drop",
-        TerminatorKind::DropAndReplace { .. } => "DropAndReplace",
         TerminatorKind::Call { .. } => "Call",
         TerminatorKind::Assert { .. } => "Assert",
         TerminatorKind::Yield { .. } => "Yield",
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index a2671eef2e9..c03cacd8615 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -156,7 +156,6 @@ impl CoverageGraph {
                 | TerminatorKind::Resume
                 | TerminatorKind::Unreachable
                 | TerminatorKind::Drop { .. }
-                | TerminatorKind::DropAndReplace { .. }
                 | TerminatorKind::Call { .. }
                 | TerminatorKind::GeneratorDrop
                 | TerminatorKind::Assert { .. }
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 8ee316773ae..d9f68f5d93a 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -850,7 +850,6 @@ pub(super) fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Sp
         TerminatorKind::Unreachable // Unreachable blocks are not connected to the MIR CFG
         | TerminatorKind::Assert { .. }
         | TerminatorKind::Drop { .. }
-        | TerminatorKind::DropAndReplace { .. }
         | TerminatorKind::SwitchInt { .. }
         // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`.
         | TerminatorKind::FalseEdge { .. }
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index fa7f22303a8..aded8039dc3 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -86,7 +86,6 @@ impl<'tcx> MockBlocks<'tcx> {
             TerminatorKind::Assert { ref mut target, .. }
             | TerminatorKind::Call { target: Some(ref mut target), .. }
             | TerminatorKind::Drop { ref mut target, .. }
-            | TerminatorKind::DropAndReplace { ref mut target, .. }
             | TerminatorKind::FalseEdge { real_target: ref mut target, .. }
             | TerminatorKind::FalseUnwind { real_target: ref mut target, .. }
             | TerminatorKind::Goto { ref mut target }
@@ -184,7 +183,6 @@ fn debug_basic_blocks(mir_body: &Body<'_>) -> String {
                     TerminatorKind::Assert { target, .. }
                     | TerminatorKind::Call { target: Some(target), .. }
                     | TerminatorKind::Drop { target, .. }
-                    | TerminatorKind::DropAndReplace { target, .. }
                     | TerminatorKind::FalseEdge { real_target: target, .. }
                     | TerminatorKind::FalseUnwind { real_target: target, .. }
                     | TerminatorKind::Goto { target }
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 2e481b97278..3823b6201c3 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -650,8 +650,7 @@ impl WriteInfo {
             TerminatorKind::Drop { .. } => {
                 // `Drop`s create a `&mut` and so are not considered
             }
-            TerminatorKind::DropAndReplace { .. }
-            | TerminatorKind::Yield { .. }
+            TerminatorKind::Yield { .. }
             | TerminatorKind::GeneratorDrop
             | TerminatorKind::FalseEdge { .. }
             | TerminatorKind::FalseUnwind { .. } => {
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index 29424f09695..3faccca823a 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -18,15 +18,14 @@ use rustc_span::{DesugaringKind, Span};
 use rustc_target::abi::VariantIdx;
 use std::fmt;
 
-/// During MIR building, Drop and DropAndReplace terminators are inserted in every place where a drop may occur.
+/// During MIR building, Drop terminators are inserted in every place where a drop may occur.
 /// However, in this phase, the presence of these terminators does not guarantee that a destructor will run,
 /// as the target of the drop may be uninitialized.
 /// In general, the compiler cannot determine at compile time whether a destructor will run or not.
 ///
-/// At a high level, this pass refines Drop and DropAndReplace to only run the destructor if the
+/// At a high level, this pass refines Drop to only run the destructor if the
 /// target is initialized. The way this is achievied is by inserting drop flags for every variable
 /// that may be dropped, and then using those flags to determine whether a destructor should run.
-/// This pass also removes DropAndReplace, replacing it with a Drop paired with an assign statement.
 /// Once this is complete, Drop terminators in the MIR correspond to a call to the "drop glue" or
 /// "drop shim" for the type of the dropped place.
 ///
@@ -121,8 +120,7 @@ fn remove_dead_unwinds<'tcx>(
         .into_results_cursor(body);
     for (bb, bb_data) in body.basic_blocks.iter_enumerated() {
         let place = match bb_data.terminator().kind {
-            TerminatorKind::Drop { ref place, unwind: Some(_), .. }
-            | TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => {
+            TerminatorKind::Drop { ref place, unwind: Some(_), .. } => {
                 und.derefer(place.as_ref(), body).unwrap_or(*place)
             }
             _ => continue,
@@ -343,8 +341,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
             }
             let terminator = data.terminator();
             let place = match terminator.kind {
-                TerminatorKind::Drop { ref place, .. }
-                | TerminatorKind::DropAndReplace { ref place, .. } => {
+                TerminatorKind::Drop { ref place, .. } => {
                     self.un_derefer.derefer(place.as_ref(), self.body).unwrap_or(*place)
                 }
                 _ => continue,
@@ -441,103 +438,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                         }
                     }
                 }
-                TerminatorKind::DropAndReplace { mut place, ref value, target, unwind } => {
-                    assert!(!data.is_cleanup);
-
-                    if let Some(new_place) = self.un_derefer.derefer(place.as_ref(), self.body) {
-                        place = new_place;
-                    }
-                    self.elaborate_replace(loc, place, value, target, unwind);
-                }
                 _ => continue,
             }
         }
     }
 
-    /// Elaborate a MIR `replace` terminator. This instruction
-    /// is not directly handled by codegen, and therefore
-    /// must be desugared.
-    ///
-    /// The desugaring drops the location if needed, and then writes
-    /// the value (including setting the drop flag) over it in *both* arms.
-    ///
-    /// The `replace` terminator can also be called on places that
-    /// are not tracked by elaboration (for example,
-    /// `replace x[i] <- tmp0`). The borrow checker requires that
-    /// these locations are initialized before the assignment,
-    /// so we just generate an unconditional drop.
-    fn elaborate_replace(
-        &mut self,
-        loc: Location,
-        place: Place<'tcx>,
-        value: &Operand<'tcx>,
-        target: BasicBlock,
-        unwind: Option<BasicBlock>,
-    ) {
-        let bb = loc.block;
-        let data = &self.body[bb];
-        let terminator = data.terminator();
-        assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported");
-
-        let assign = Statement {
-            kind: StatementKind::Assign(Box::new((place, Rvalue::Use(value.clone())))),
-            source_info: terminator.source_info,
-        };
-
-        let unwind = unwind.unwrap_or_else(|| self.patch.resume_block());
-        let unwind = self.patch.new_block(BasicBlockData {
-            statements: vec![assign.clone()],
-            terminator: Some(Terminator {
-                kind: TerminatorKind::Goto { target: unwind },
-                ..*terminator
-            }),
-            is_cleanup: true,
-        });
-
-        let target = self.patch.new_block(BasicBlockData {
-            statements: vec![assign],
-            terminator: Some(Terminator { kind: TerminatorKind::Goto { target }, ..*terminator }),
-            is_cleanup: false,
-        });
-
-        match self.move_data().rev_lookup.find(place.as_ref()) {
-            LookupResult::Exact(path) => {
-                debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path);
-                self.init_data.seek_before(loc);
-                elaborate_drop(
-                    &mut Elaborator { ctxt: self },
-                    terminator.source_info,
-                    place,
-                    path,
-                    target,
-                    Unwind::To(unwind),
-                    bb,
-                );
-                on_all_children_bits(self.tcx, self.body, self.move_data(), path, |child| {
-                    self.set_drop_flag(
-                        Location { block: target, statement_index: 0 },
-                        child,
-                        DropFlagState::Present,
-                    );
-                    self.set_drop_flag(
-                        Location { block: unwind, statement_index: 0 },
-                        child,
-                        DropFlagState::Present,
-                    );
-                });
-            }
-            LookupResult::Parent(parent) => {
-                // drop and replace behind a pointer/array/whatever. The location
-                // must be initialized.
-                debug!("elaborate_drop_and_replace({:?}) - untracked {:?}", terminator, parent);
-                self.patch.patch_terminator(
-                    bb,
-                    TerminatorKind::Drop { place, target, unwind: Some(unwind) },
-                );
-            }
-        }
-    }
-
     fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> {
         Rvalue::Use(Operand::Constant(Box::new(Constant {
             span,
@@ -609,22 +514,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
             debug!("drop_flags_for_locs({:?})", data);
             for i in 0..(data.statements.len() + 1) {
                 debug!("drop_flag_for_locs: stmt {}", i);
-                let mut allow_initializations = true;
                 if i == data.statements.len() {
                     match data.terminator().kind {
                         TerminatorKind::Drop { .. } => {
                             // drop elaboration should handle that by itself
                             continue;
                         }
-                        TerminatorKind::DropAndReplace { .. } => {
-                            // this contains the move of the source and
-                            // the initialization of the destination. We
-                            // only want the former - the latter is handled
-                            // by the elaboration code and must be done
-                            // *after* the destination is dropped.
-                            assert!(self.patch.is_patched(bb));
-                            allow_initializations = false;
-                        }
                         TerminatorKind::Resume => {
                             // It is possible for `Resume` to be patched
                             // (in particular it can be patched to be replaced with
@@ -641,11 +536,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                     self.body,
                     self.env,
                     loc,
-                    |path, ds| {
-                        if ds == DropFlagState::Absent || allow_initializations {
-                            self.set_drop_flag(loc, path, ds)
-                        }
-                    },
+                    |path, ds| self.set_drop_flag(loc, path, ds),
                 )
             }
 
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index 746326f9bde..129f366bcd0 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -1199,7 +1199,6 @@ fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
 
             // These may unwind.
             TerminatorKind::Drop { .. }
-            | TerminatorKind::DropAndReplace { .. }
             | TerminatorKind::Call { .. }
             | TerminatorKind::InlineAsm { .. }
             | TerminatorKind::Assert { .. } => return true,
@@ -1691,7 +1690,6 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
             | TerminatorKind::Return
             | TerminatorKind::Unreachable
             | TerminatorKind::Drop { .. }
-            | TerminatorKind::DropAndReplace { .. }
             | TerminatorKind::Assert { .. }
             | TerminatorKind::GeneratorDrop
             | TerminatorKind::FalseEdge { .. }
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 6e6d6566f4b..9cba8870f23 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -453,9 +453,7 @@ impl<'tcx> Inliner<'tcx> {
             checker.visit_basic_block_data(bb, blk);
 
             let term = blk.terminator();
-            if let TerminatorKind::Drop { ref place, target, unwind }
-            | TerminatorKind::DropAndReplace { ref place, target, unwind, .. } = term.kind
-            {
+            if let TerminatorKind::Drop { ref place, target, unwind } = term.kind {
                 work_list.push(target);
 
                 // If the place doesn't actually need dropping, treat it like a regular goto.
@@ -815,8 +813,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
     fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
         let tcx = self.tcx;
         match terminator.kind {
-            TerminatorKind::Drop { ref place, unwind, .. }
-            | TerminatorKind::DropAndReplace { ref place, unwind, .. } => {
+            TerminatorKind::Drop { ref place, unwind, .. } => {
                 // If the place doesn't actually need dropping, treat it like a regular goto.
                 let ty = self.instance.subst_mir(tcx, &place.ty(self.callee_body, tcx).ty);
                 if ty.needs_drop(tcx, self.param_env) {
@@ -1120,8 +1117,7 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
                     *tgt = self.map_block(*tgt);
                 }
             }
-            TerminatorKind::Drop { ref mut target, ref mut unwind, .. }
-            | TerminatorKind::DropAndReplace { ref mut target, ref mut unwind, .. } => {
+            TerminatorKind::Drop { ref mut target, ref mut unwind, .. } => {
                 *target = self.map_block(*target);
                 *unwind = self.map_unwind(*unwind);
             }
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index e3a03aa08af..6c067f45299 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -75,7 +75,6 @@ impl RemoveNoopLandingPads {
             | TerminatorKind::Unreachable
             | TerminatorKind::Call { .. }
             | TerminatorKind::Assert { .. }
-            | TerminatorKind::DropAndReplace { .. }
             | TerminatorKind::Drop { .. }
             | TerminatorKind::InlineAsm { .. } => false,
         }
diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
index 78b6f714a9b..e72729b152e 100644
--- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
@@ -1,5 +1,5 @@
 use rustc_index::bit_set::ChunkedBitSet;
-use rustc_middle::mir::{Body, Field, Rvalue, Statement, StatementKind, TerminatorKind};
+use rustc_middle::mir::{Body, Field, TerminatorKind};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, VariantDef};
 use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
@@ -8,7 +8,7 @@ use rustc_mir_dataflow::{self, move_path_children_matching, Analysis, MoveDataPa
 
 use crate::MirPass;
 
-/// Removes `Drop` and `DropAndReplace` terminators whose target is known to be uninitialized at
+/// Removes `Drop` terminators whose target is known to be uninitialized at
 /// that point.
 ///
 /// This is redundant with drop elaboration, but we need to do it prior to const-checking, and
@@ -37,8 +37,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUninitDrops {
         let mut to_remove = vec![];
         for (bb, block) in body.basic_blocks.iter_enumerated() {
             let terminator = block.terminator();
-            let (TerminatorKind::Drop { place, .. } | TerminatorKind::DropAndReplace { place, .. })
-                = &terminator.kind
+            let TerminatorKind::Drop { place, .. } = &terminator.kind
             else { continue };
 
             maybe_inits.seek_before_primary_effect(body.terminator_loc(bb));
@@ -64,24 +63,12 @@ impl<'tcx> MirPass<'tcx> for RemoveUninitDrops {
         for bb in to_remove {
             let block = &mut body.basic_blocks_mut()[bb];
 
-            let (TerminatorKind::Drop { target, .. } | TerminatorKind::DropAndReplace { target, .. })
+            let TerminatorKind::Drop { target, .. }
                 = &block.terminator().kind
             else { unreachable!() };
 
             // Replace block terminator with `Goto`.
-            let target = *target;
-            let old_terminator_kind = std::mem::replace(
-                &mut block.terminator_mut().kind,
-                TerminatorKind::Goto { target },
-            );
-
-            // If this is a `DropAndReplace`, we need to emulate the assignment to the return place.
-            if let TerminatorKind::DropAndReplace { place, value, .. } = old_terminator_kind {
-                block.statements.push(Statement {
-                    source_info: block.terminator().source_info,
-                    kind: StatementKind::Assign(Box::new((place, Rvalue::Use(value)))),
-                });
-            }
+            block.terminator_mut().kind = TerminatorKind::Goto { target: *target };
         }
     }
 }
diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs
index a24d2d34d79..c3f5b881ab8 100644
--- a/compiler/rustc_mir_transform/src/separate_const_switch.rs
+++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs
@@ -108,7 +108,6 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
                         // The following terminators are not allowed
                         TerminatorKind::Resume
                         | TerminatorKind::Drop { .. }
-                        | TerminatorKind::DropAndReplace { .. }
                         | TerminatorKind::Call { .. }
                         | TerminatorKind::Assert { .. }
                         | TerminatorKind::FalseUnwind { .. }
@@ -170,7 +169,6 @@ pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
             | TerminatorKind::Unreachable
             | TerminatorKind::GeneratorDrop
             | TerminatorKind::Assert { .. }
-            | TerminatorKind::DropAndReplace { .. }
             | TerminatorKind::FalseUnwind { .. }
             | TerminatorKind::Drop { .. }
             | TerminatorKind::Call { .. }
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 45e659eab6c..f529944acce 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -808,8 +808,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                 let callee_ty = self.monomorphize(callee_ty);
                 visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output)
             }
-            mir::TerminatorKind::Drop { ref place, .. }
-            | mir::TerminatorKind::DropAndReplace { ref place, .. } => {
+            mir::TerminatorKind::Drop { ref place, .. } => {
                 let ty = place.ty(self.body, self.tcx).ty;
                 let ty = self.monomorphize(ty);
                 visit_drop_use(self.tcx, ty, true, source, self.output);
diff --git a/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs
index c048d4a2aad..981a8f45e45 100644
--- a/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs
@@ -261,12 +261,23 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
         self.interner().mk_re_late_bound(self.binder_index, br)
     }
 
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+    fn fold_ty(&mut self, mut t: Ty<'tcx>) -> Ty<'tcx> {
         let kind = match *t.kind() {
-            ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) {
-                Ok(t) => return self.fold_ty(t),
-                Err(ui) => CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
-            },
+            ty::Infer(ty::TyVar(mut vid)) => {
+                // We need to canonicalize the *root* of our ty var.
+                // This is so that our canonical response correctly reflects
+                // any equated inference vars correctly!
+                let root_vid = self.infcx.root_var(vid);
+                if root_vid != vid {
+                    t = self.infcx.tcx.mk_ty_var(root_vid);
+                    vid = root_vid;
+                }
+
+                match self.infcx.probe_ty_var(vid) {
+                    Ok(t) => return self.fold_ty(t),
+                    Err(ui) => CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
+                }
+            }
             ty::Infer(ty::IntVar(_)) => {
                 let nt = self.infcx.shallow_resolve(t);
                 if nt != t {
@@ -338,13 +349,23 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
         self.interner().mk_bound(self.binder_index, bt)
     }
 
-    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
+    fn fold_const(&mut self, mut c: ty::Const<'tcx>) -> ty::Const<'tcx> {
         let kind = match c.kind() {
-            ty::ConstKind::Infer(ty::InferConst::Var(vid)) => match self.infcx.probe_const_var(vid)
-            {
-                Ok(c) => return self.fold_const(c),
-                Err(universe) => CanonicalVarKind::Const(universe, c.ty()),
-            },
+            ty::ConstKind::Infer(ty::InferConst::Var(mut vid)) => {
+                // We need to canonicalize the *root* of our const var.
+                // This is so that our canonical response correctly reflects
+                // any equated inference vars correctly!
+                let root_vid = self.infcx.root_const_var(vid);
+                if root_vid != vid {
+                    c = self.infcx.tcx.mk_const(ty::InferConst::Var(root_vid), c.ty());
+                    vid = root_vid;
+                }
+
+                match self.infcx.probe_const_var(vid) {
+                    Ok(c) => return self.fold_const(c),
+                    Err(universe) => CanonicalVarKind::Const(universe, c.ty()),
+                }
+            }
             ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => {
                 bug!("fresh var during canonicalization: {c:?}")
             }
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 57b6a452737..43fd415e871 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -238,6 +238,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             && has_changed
             && !self.in_projection_eq_hack
             && !self.search_graph.in_cycle()
+            && false
         {
             let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
             let canonical_response =
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 0e047977caa..62bad5b49b4 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -155,10 +155,12 @@ fn pred_known_to_hold_modulo_regions<'tcx>(
         predicate: pred.to_predicate(infcx.tcx),
     };
 
-    let result = infcx.predicate_must_hold_modulo_regions(&obligation);
+    let result = infcx.evaluate_obligation_no_overflow(&obligation);
     debug!(?result);
 
-    if result && has_non_region_infer {
+    if result.must_apply_modulo_regions() && !has_non_region_infer {
+        true
+    } else if result.may_apply() {
         // Because of inference "guessing", selection can sometimes claim
         // to succeed while the success requires a guess. To ensure
         // this function's result remains infallible, we must confirm
@@ -179,7 +181,7 @@ fn pred_known_to_hold_modulo_regions<'tcx>(
             }
         }
     } else {
-        result
+        false
     }
 }
 
diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs
index 72db1d87ca3..d2d9771bdce 100644
--- a/library/core/src/intrinsics/mir.rs
+++ b/library/core/src/intrinsics/mir.rs
@@ -227,7 +227,7 @@
 //! are no resume and abort terminators, and terminators that might unwind do not have any way to
 //! indicate the unwind block.
 //!
-//!  - [`Goto`], [`Return`], [`Unreachable`], [`Drop`](Drop()), and [`DropAndReplace`] have associated functions.
+//!  - [`Goto`], [`Return`], [`Unreachable`] and [`Drop`](Drop()) have associated functions.
 //!  - `match some_int_operand` becomes a `SwitchInt`. Each arm should be `literal => basic_block`
 //!     - The exception is the last arm, which must be `_ => basic_block` and corresponds to the
 //!       otherwise branch.
@@ -259,7 +259,6 @@ define!("mir_return", fn Return() -> BasicBlock);
 define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
 define!("mir_unreachable", fn Unreachable() -> BasicBlock);
 define!("mir_drop", fn Drop<T>(place: T, goto: BasicBlock));
-define!("mir_drop_and_replace", fn DropAndReplace<T>(place: T, value: T, goto: BasicBlock));
 define!("mir_call", fn Call<T>(place: T, goto: BasicBlock, call: T));
 define!("mir_storage_live", fn StorageLive<T>(local: T));
 define!("mir_storage_dead", fn StorageDead<T>(local: T));
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 9b5e116aa5c..47d742ef796 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -1721,6 +1721,15 @@ impl<'a> Builder<'a> {
 
         cargo.env("RUSTC_VERBOSE", self.verbosity.to_string());
 
+        // Downstream forks of the Rust compiler might want to use a custom libc to add support for
+        // targets that are not yet available upstream. Adding a patch to replace libc with a
+        // custom one would cause compilation errors though, because Cargo would interpret the
+        // custom libc as part of the workspace, and apply the check-cfg lints on it.
+        //
+        // The libc build script emits check-cfg flags only when this environment variable is set,
+        // so this line allows the use of custom libcs.
+        cargo.env("LIBC_CHECK_CFG", "1");
+
         if source_type == SourceType::InTree {
             let mut lint_flags = Vec::new();
             // When extending this list, add the new lints to the RUSTFLAGS of the
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 1a35fe05067..c00800291db 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -299,10 +299,6 @@ fn check_terminator<'tcx>(
         | TerminatorKind::Unreachable => Ok(()),
 
         TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, body),
-        TerminatorKind::DropAndReplace { place, value, .. } => {
-            check_place(tcx, *place, span, body)?;
-            check_operand(tcx, value, span, body)
-        },
 
         TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body),
 
diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js
index 2f0ca1ec3d0..80bfd38d1e9 100644
--- a/src/tools/rustdoc-gui/tester.js
+++ b/src/tools/rustdoc-gui/tester.js
@@ -31,7 +31,7 @@ function isNumeric(s) {
 }
 
 function parseOptions(args) {
-    var opts = {
+    const opts = {
         "doc_folder": "",
         "tests_folder": "",
         "files": [],
@@ -42,7 +42,7 @@ function parseOptions(args) {
         "executable_path": null,
         "no_sandbox": false,
     };
-    var correspondances = {
+    const correspondances = {
         "--doc-folder": "doc_folder",
         "--tests-folder": "tests_folder",
         "--debug": "debug",
@@ -52,39 +52,41 @@ function parseOptions(args) {
         "--no-sandbox": "no_sandbox",
     };
 
-    for (var i = 0; i < args.length; ++i) {
-        if (args[i] === "--doc-folder"
-            || args[i] === "--tests-folder"
-            || args[i] === "--file"
-            || args[i] === "--jobs"
-            || args[i] === "--executable-path") {
+    for (let i = 0; i < args.length; ++i) {
+        const arg = args[i];
+        if (arg === "--doc-folder"
+            || arg === "--tests-folder"
+            || arg === "--file"
+            || arg === "--jobs"
+            || arg === "--executable-path") {
             i += 1;
             if (i >= args.length) {
-                console.log("Missing argument after `" + args[i - 1] + "` option.");
+                console.log("Missing argument after `" + arg + "` option.");
                 return null;
             }
-            if (args[i - 1] === "--jobs") {
-                if (!isNumeric(args[i])) {
+            const arg_value = args[i];
+            if (arg === "--jobs") {
+                if (!isNumeric(arg_value)) {
                     console.log(
-                        "`--jobs` option expects a positive number, found `" + args[i] + "`");
+                        "`--jobs` option expects a positive number, found `" + arg_value + "`");
                     return null;
                 }
-                opts["jobs"] = parseInt(args[i]);
-            } else if (args[i - 1] !== "--file") {
-                opts[correspondances[args[i - 1]]] = args[i];
+                opts["jobs"] = parseInt(arg_value);
+            } else if (arg !== "--file") {
+                opts[correspondances[arg]] = arg_value;
             } else {
-                opts["files"].push(args[i]);
+                opts["files"].push(arg_value);
             }
-        } else if (args[i] === "--help") {
+        } else if (arg === "--help") {
             showHelp();
             process.exit(0);
-        } else if (args[i] === "--no-sandbox") {
+        } else if (arg === "--no-sandbox") {
             console.log("`--no-sandbox` is being used. Be very careful!");
-            opts[correspondances[args[i]]] = true;
-        } else if (correspondances[args[i]]) {
-            opts[correspondances[args[i]]] = true;
+            opts[correspondances[arg]] = true;
+        } else if (correspondances[arg]) {
+            opts[correspondances[arg]] = true;
         } else {
-            console.log("Unknown option `" + args[i] + "`.");
+            console.log("Unknown option `" + arg + "`.");
             console.log("Use `--help` to see the list of options");
             return null;
         }
@@ -186,7 +188,7 @@ function createEmptyResults() {
 }
 
 async function main(argv) {
-    let opts = parseOptions(argv.slice(2));
+    const opts = parseOptions(argv.slice(2));
     if (opts === null) {
         process.exit(1);
     }
diff --git a/tests/mir-opt/building/custom/terminators.drop_first.built.after.mir b/tests/mir-opt/building/custom/terminators.drop_first.built.after.mir
index c903e594696..ada78c0fc78 100644
--- a/tests/mir-opt/building/custom/terminators.drop_first.built.after.mir
+++ b/tests/mir-opt/building/custom/terminators.drop_first.built.after.mir
@@ -4,10 +4,11 @@ fn drop_first(_1: WriteOnDrop<'_>, _2: WriteOnDrop<'_>) -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/terminators.rs:+0:59: +0:59
 
     bb0: {
-        replace(_1 <- move _2) -> bb1;   // scope 0 at $DIR/terminators.rs:+3:13: +3:49
+        drop(_1) -> bb1;                 // scope 0 at $DIR/terminators.rs:+3:13: +3:30
     }
 
     bb1: {
-        return;                          // scope 0 at $DIR/terminators.rs:+7:13: +7:21
+        _1 = move _2;                    // scope 0 at $DIR/terminators.rs:+7:13: +7:24
+        return;                          // scope 0 at $DIR/terminators.rs:+8:13: +8:21
     }
 }
diff --git a/tests/mir-opt/building/custom/terminators.rs b/tests/mir-opt/building/custom/terminators.rs
index c23233fcf9a..f1240566168 100644
--- a/tests/mir-opt/building/custom/terminators.rs
+++ b/tests/mir-opt/building/custom/terminators.rs
@@ -48,10 +48,11 @@ impl<'a> Drop for WriteOnDrop<'a> {
 fn drop_first<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) {
     mir!(
         {
-            DropAndReplace(a, Move(b), retblock)
+            Drop(a, retblock)
         }
 
         retblock = {
+            a = Move(b);
             Return()
         }
     )
diff --git a/tests/ui/traits/new-solver/canonical-ty-var-eq-in-response.rs b/tests/ui/traits/new-solver/canonical-ty-var-eq-in-response.rs
new file mode 100644
index 00000000000..d1c6b1077e8
--- /dev/null
+++ b/tests/ui/traits/new-solver/canonical-ty-var-eq-in-response.rs
@@ -0,0 +1,39 @@
+// check-pass
+// compile-flags: -Ztrait-solver=next
+
+trait Mirror {
+    type Item;
+}
+
+struct Wrapper<T>(T);
+impl<T> Mirror for Wrapper<T> {
+    type Item = T;
+}
+
+fn mirror<T>()
+where
+    Wrapper<T>: Mirror<Item = i32>,
+{
+}
+
+fn main() {
+    mirror::<_ /* ?0 */>();
+
+    // Solving `<Wrapper<?0> as Mirror>::Item = i32`
+
+    // First, we replace the term with a fresh infer var:
+    // `<Wrapper<?0> as Mirror>::Item = ?1`
+
+    // We select the impl candidate on line #6, which leads us to learn that
+    // `?0 == ?1`.
+
+    // That should be reflected in our canonical response, which should have
+    // `^0 = ^0, ^1 = ^0`
+    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+    // !! We used to return a totally unconstrained response here :< !!
+    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+    // Then, during the "equate term" part of the projection solving, we
+    // instantiate the response from the unconstrained projection predicate,
+    // and equate `?0 == i32`.
+}
diff --git a/tests/ui/traits/new-solver/deduce-ty-from-object.rs b/tests/ui/traits/new-solver/deduce-ty-from-object.rs
new file mode 100644
index 00000000000..7398bce7b61
--- /dev/null
+++ b/tests/ui/traits/new-solver/deduce-ty-from-object.rs
@@ -0,0 +1,6 @@
+// check-pass
+// compile-flags: -Ztrait-solver=next
+
+fn main() {
+    let x: Box<dyn Iterator<Item = ()>> = Box::new(std::iter::empty());
+}
diff --git a/tests/ui/union/field_checks.rs b/tests/ui/union/field_checks.rs
index d5d1e44ac85..bb4eccb4cf8 100644
--- a/tests/ui/union/field_checks.rs
+++ b/tests/ui/union/field_checks.rs
@@ -21,15 +21,15 @@ union U24<T> { // OK
 }
 
 union U3 {
-    a: String, //~ ERROR unions cannot contain fields that may need dropping
+    a: String, //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
 }
 
 union U32 { // field that does not drop but is not `Copy`, either
-    a: std::cell::RefCell<i32>, //~ ERROR unions cannot contain fields that may need dropping
+    a: std::cell::RefCell<i32>, //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
 }
 
 union U4<T> {
-    a: T, //~ ERROR unions cannot contain fields that may need dropping
+    a: T, //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
 }
 
 union U5 { // Having a drop impl is OK
@@ -41,11 +41,11 @@ impl Drop for U5 {
 }
 
 union U5Nested { // a nested union that drops is NOT OK
-    nest: U5, //~ ERROR unions cannot contain fields that may need dropping
+    nest: U5, //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
 }
 
 union U5Nested2 { // for now we don't special-case empty arrays
-    nest: [U5; 0], //~ ERROR unions cannot contain fields that may need dropping
+    nest: [U5; 0], //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
 }
 
 union U6 { // OK
diff --git a/tests/ui/union/field_checks.stderr b/tests/ui/union/field_checks.stderr
index 1f97e97ac6e..32407a74970 100644
--- a/tests/ui/union/field_checks.stderr
+++ b/tests/ui/union/field_checks.stderr
@@ -1,59 +1,59 @@
-error[E0740]: unions cannot contain fields that may need dropping
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
   --> $DIR/field_checks.rs:24:5
    |
 LL |     a: String,
    |     ^^^^^^^^^
    |
-   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
-help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
    |
 LL |     a: std::mem::ManuallyDrop<String>,
    |        +++++++++++++++++++++++      +
 
-error[E0740]: unions cannot contain fields that may need dropping
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
   --> $DIR/field_checks.rs:28:5
    |
 LL |     a: std::cell::RefCell<i32>,
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
-help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
    |
 LL |     a: std::mem::ManuallyDrop<std::cell::RefCell<i32>>,
    |        +++++++++++++++++++++++                       +
 
-error[E0740]: unions cannot contain fields that may need dropping
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
   --> $DIR/field_checks.rs:32:5
    |
 LL |     a: T,
    |     ^^^^
    |
-   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
-help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
    |
 LL |     a: std::mem::ManuallyDrop<T>,
    |        +++++++++++++++++++++++ +
 
-error[E0740]: unions cannot contain fields that may need dropping
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
   --> $DIR/field_checks.rs:44:5
    |
 LL |     nest: U5,
    |     ^^^^^^^^
    |
-   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
-help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
    |
 LL |     nest: std::mem::ManuallyDrop<U5>,
    |           +++++++++++++++++++++++  +
 
-error[E0740]: unions cannot contain fields that may need dropping
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
   --> $DIR/field_checks.rs:48:5
    |
 LL |     nest: [U5; 0],
    |     ^^^^^^^^^^^^^
    |
-   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
-help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
    |
 LL |     nest: std::mem::ManuallyDrop<[U5; 0]>,
    |           +++++++++++++++++++++++       +
diff --git a/tests/ui/union/issue-41073.rs b/tests/ui/union/issue-41073.rs
index 4dfdc606bb4..f7a82b4e7cf 100644
--- a/tests/ui/union/issue-41073.rs
+++ b/tests/ui/union/issue-41073.rs
@@ -1,5 +1,5 @@
 union Test {
-    a: A, //~ ERROR unions cannot contain fields that may need dropping
+    a: A, //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
     b: B
 }
 
diff --git a/tests/ui/union/issue-41073.stderr b/tests/ui/union/issue-41073.stderr
index b3887fa0f90..ae1c4dfed9a 100644
--- a/tests/ui/union/issue-41073.stderr
+++ b/tests/ui/union/issue-41073.stderr
@@ -1,11 +1,11 @@
-error[E0740]: unions cannot contain fields that may need dropping
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
   --> $DIR/issue-41073.rs:2:5
    |
 LL |     a: A,
    |     ^^^^
    |
-   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
-help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
    |
 LL |     a: std::mem::ManuallyDrop<A>,
    |        +++++++++++++++++++++++ +
diff --git a/tests/ui/union/union-with-drop-fields.mirunsafeck.stderr b/tests/ui/union/union-with-drop-fields.mirunsafeck.stderr
index 93fe996d2a4..9861a21cb3d 100644
--- a/tests/ui/union/union-with-drop-fields.mirunsafeck.stderr
+++ b/tests/ui/union/union-with-drop-fields.mirunsafeck.stderr
@@ -1,35 +1,35 @@
-error[E0740]: unions cannot contain fields that may need dropping
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
   --> $DIR/union-with-drop-fields.rs:11:5
    |
 LL |     a: String,
    |     ^^^^^^^^^
    |
-   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
-help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
    |
 LL |     a: std::mem::ManuallyDrop<String>,
    |        +++++++++++++++++++++++      +
 
-error[E0740]: unions cannot contain fields that may need dropping
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
   --> $DIR/union-with-drop-fields.rs:19:5
    |
 LL |     a: S,
    |     ^^^^
    |
-   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
-help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
    |
 LL |     a: std::mem::ManuallyDrop<S>,
    |        +++++++++++++++++++++++ +
 
-error[E0740]: unions cannot contain fields that may need dropping
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
   --> $DIR/union-with-drop-fields.rs:24:5
    |
 LL |     a: T,
    |     ^^^^
    |
-   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
-help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
    |
 LL |     a: std::mem::ManuallyDrop<T>,
    |        +++++++++++++++++++++++ +
diff --git a/tests/ui/union/union-with-drop-fields.rs b/tests/ui/union/union-with-drop-fields.rs
index a7a8b69e784..9720830fb1f 100644
--- a/tests/ui/union/union-with-drop-fields.rs
+++ b/tests/ui/union/union-with-drop-fields.rs
@@ -8,7 +8,7 @@ union U {
 }
 
 union W {
-    a: String, //~ ERROR unions cannot contain fields that may need dropping
+    a: String, //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
     b: String, // OK, only one field is reported
 }
 
@@ -16,12 +16,12 @@ struct S(String);
 
 // `S` doesn't implement `Drop` trait, but still has non-trivial destructor
 union Y {
-    a: S, //~ ERROR unions cannot contain fields that may need dropping
+    a: S, //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
 }
 
 // We don't know if `T` is trivially-destructable or not until trans
 union J<T> {
-    a: T, //~ ERROR unions cannot contain fields that may need dropping
+    a: T, //~ ERROR field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
 }
 
 union H<T: Copy> {
diff --git a/tests/ui/union/union-with-drop-fields.thirunsafeck.stderr b/tests/ui/union/union-with-drop-fields.thirunsafeck.stderr
index 93fe996d2a4..9861a21cb3d 100644
--- a/tests/ui/union/union-with-drop-fields.thirunsafeck.stderr
+++ b/tests/ui/union/union-with-drop-fields.thirunsafeck.stderr
@@ -1,35 +1,35 @@
-error[E0740]: unions cannot contain fields that may need dropping
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
   --> $DIR/union-with-drop-fields.rs:11:5
    |
 LL |     a: String,
    |     ^^^^^^^^^
    |
-   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
-help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
    |
 LL |     a: std::mem::ManuallyDrop<String>,
    |        +++++++++++++++++++++++      +
 
-error[E0740]: unions cannot contain fields that may need dropping
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
   --> $DIR/union-with-drop-fields.rs:19:5
    |
 LL |     a: S,
    |     ^^^^
    |
-   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
-help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
    |
 LL |     a: std::mem::ManuallyDrop<S>,
    |        +++++++++++++++++++++++ +
 
-error[E0740]: unions cannot contain fields that may need dropping
+error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
   --> $DIR/union-with-drop-fields.rs:24:5
    |
 LL |     a: T,
    |     ^^^^
    |
-   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
-help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+   = note: union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+help: wrap the field type in `ManuallyDrop<...>`
    |
 LL |     a: std::mem::ManuallyDrop<T>,
    |        +++++++++++++++++++++++ +
diff --git a/tests/ui/union/unresolved-field-isnt-copy.rs b/tests/ui/union/unresolved-field-isnt-copy.rs
new file mode 100644
index 00000000000..7a6d79b2faa
--- /dev/null
+++ b/tests/ui/union/unresolved-field-isnt-copy.rs
@@ -0,0 +1,8 @@
+// Unresolved fields are not copy, but also shouldn't report an extra E0740.
+
+pub union Foo {
+    x: *const Missing,
+    //~^ ERROR cannot find type `Missing` in this scope
+}
+
+fn main() {}
diff --git a/tests/ui/union/unresolved-field-isnt-copy.stderr b/tests/ui/union/unresolved-field-isnt-copy.stderr
new file mode 100644
index 00000000000..22301582eef
--- /dev/null
+++ b/tests/ui/union/unresolved-field-isnt-copy.stderr
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `Missing` in this scope
+  --> $DIR/unresolved-field-isnt-copy.rs:4:15
+   |
+LL |     x: *const Missing,
+   |               ^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.