about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs2
-rw-r--r--compiler/rustc_ast/src/lib.rs2
-rw-r--r--compiler/rustc_ast/src/ptr.rs9
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs54
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs1
-rw-r--r--compiler/rustc_borrowck/src/def_use.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs40
-rw-r--r--compiler/rustc_borrowck/src/invalidation.rs6
-rw-r--r--compiler/rustc_borrowck/src/lib.rs6
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs25
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/analyze.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/statement.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs5
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs36
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs5
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs1
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs250
-rw-r--r--compiler/rustc_const_eval/src/util/aggregate.rs53
-rw-r--r--compiler/rustc_error_messages/locales/en-US/diagnostics.ftl1
-rw-r--r--compiler/rustc_error_messages/src/lib.rs69
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs38
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs3
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs2
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_interface/src/util.rs14
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp7
-rw-r--r--compiler/rustc_metadata/src/lib.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs58
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs48
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs42
-rw-r--r--compiler/rustc_metadata/src/rmeta/table.rs314
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs363
-rw-r--r--compiler/rustc_middle/src/mir/spanview.rs1
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs3
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs150
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs13
-rw-r--r--compiler/rustc_middle/src/ty/error.rs124
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/init_locals.rs7
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs32
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs4
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs1
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs4
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs1
-rw-r--r--compiler/rustc_mir_transform/src/deref_separator.rs16
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs1
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs1
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs1
-rw-r--r--compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs1
-rw-r--r--compiler/rustc_mir_transform/src/remove_zsts.rs4
-rw-r--r--compiler/rustc_mir_transform/src/separate_const_switch.rs2
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs8
-rw-r--r--compiler/rustc_parse/src/parser/item.rs2
-rw-r--r--compiler/rustc_parse/src/parser/path.rs48
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs2
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs13
-rw-r--r--compiler/rustc_session/src/session.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs31
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs12
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs39
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs2
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs152
-rw-r--r--compiler/rustc_typeck/src/errors.rs7
-rw-r--r--library/alloc/src/boxed.rs16
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs18
-rw-r--r--library/alloc/tests/const_fns.rs6
-rw-r--r--library/alloc/tests/thin_box.rs2
-rw-r--r--library/core/src/alloc/layout.rs10
-rw-r--r--library/core/src/char/convert.rs139
-rw-r--r--library/core/src/char/decode.rs49
-rw-r--r--library/core/src/char/mod.rs69
-rw-r--r--library/core/src/num/mod.rs102
-rw-r--r--library/core/src/pin.rs2
-rw-r--r--library/core/src/slice/mod.rs16
-rw-r--r--library/core/src/str/converts.rs6
-rw-r--r--library/core/tests/alloc.rs2
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/core/tests/num/mod.rs71
-rw-r--r--library/std/src/os/fd/owned.rs6
-rw-r--r--library/std/src/os/fd/raw.rs2
-rw-r--r--library/std/src/sys/unix/futex.rs20
-rw-r--r--library/std/src/sys/unix/locks/futex_rwlock.rs313
-rw-r--r--library/std/src/sys/unix/locks/mod.rs4
-rw-r--r--src/bootstrap/bootstrap.py20
-rw-r--r--src/bootstrap/builder.rs6
-rw-r--r--src/bootstrap/check.rs7
-rw-r--r--src/bootstrap/compile.rs2
-rw-r--r--src/bootstrap/lib.rs4
-rwxr-xr-xsrc/ci/pgo.sh6
-rw-r--r--src/doc/rustc/src/linker-plugin-lto.md16
-rw-r--r--src/doc/rustc/src/platform-support.md10
-rwxr-xr-xsrc/etc/pre-push.sh4
-rw-r--r--src/librustdoc/clean/mod.rs12
-rw-r--r--src/librustdoc/doctest.rs8
-rw-r--r--src/librustdoc/html/markdown.rs12
-rw-r--r--src/librustdoc/theme.rs16
-rw-r--r--src/test/codegen/asm-may_unwind.rs17
-rw-r--r--src/test/codegen/try_identity.rs2
-rw-r--r--src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff1
-rw-r--r--src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff1
-rw-r--r--src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff3
-rw-r--r--src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff1
-rw-r--r--src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff1
-rw-r--r--src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff1
-rw-r--r--src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff1
-rw-r--r--src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff3
-rw-r--r--src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff1
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff1
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff1
-rw-r--r--src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff1
-rw-r--r--src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff1
-rw-r--r--src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff1
-rw-r--r--src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff1
-rw-r--r--src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff1
-rw-r--r--src/test/mir-opt/deaggregator_test.bar.Deaggregator.diff1
-rw-r--r--src/test/mir-opt/deaggregator_test_enum.bar.Deaggregator.diff1
-rw-r--r--src/test/mir-opt/deaggregator_test_enum_2.test1.Deaggregator.diff2
-rw-r--r--src/test/mir-opt/deaggregator_test_multiple.test.Deaggregator.diff2
-rw-r--r--src/test/mir-opt/derefer_test.main.Derefer.diff2
-rw-r--r--src/test/mir-opt/derefer_test_multiple.main.Derefer.diff104
-rw-r--r--src/test/mir-opt/derefer_test_multiple.rs9
-rw-r--r--src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff1
-rw-r--r--src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff1
-rw-r--r--src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff1
-rw-r--r--src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff1
-rw-r--r--src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff1
-rw-r--r--src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff12
-rw-r--r--src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff8
-rw-r--r--src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff1
-rw-r--r--src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff2
-rw-r--r--src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir3
-rw-r--r--src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir18
-rw-r--r--src/test/mir-opt/inline/cycle.f.Inline.diff1
-rw-r--r--src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir2
-rw-r--r--src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir2
-rw-r--r--src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir3
-rw-r--r--src/test/mir-opt/inline/inline_generator.main.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff1
-rw-r--r--src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff1
-rw-r--r--src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir3
-rw-r--r--src/test/mir-opt/inline/issue_78442.bar.Inline.diff1
-rw-r--r--src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff2
-rw-r--r--src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff5
-rw-r--r--src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff5
-rw-r--r--src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff5
-rw-r--r--src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff5
-rw-r--r--src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff2
-rw-r--r--src/test/mir-opt/lower_intrinsics.rs2
-rw-r--r--src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff40
-rw-r--r--src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff3
-rw-r--r--src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff3
-rw-r--r--src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff1
-rw-r--r--src/test/mir-opt/remove_zsts_dont_touch_unions.get_union.RemoveZsts.after.mir2
-rw-r--r--src/test/mir-opt/separate_const_switch.identity.ConstProp.diff5
-rw-r--r--src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir5
-rw-r--r--src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff5
-rw-r--r--src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff4
-rw-r--r--src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir4
-rw-r--r--src/test/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff4
-rw-r--r--src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff22
-rw-r--r--src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff40
-rw-r--r--src/test/mir-opt/simplify_arm.id_result.SimplifyArmIdentity.diff42
-rw-r--r--src/test/mir-opt/simplify_arm.id_result.SimplifyBranchSame.diff49
-rw-r--r--src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff59
-rw-r--r--src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff60
-rw-r--r--src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff3
-rw-r--r--src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff3
-rw-r--r--src/test/mir-opt/simplify_locals.d1.SimplifyLocals.diff1
-rw-r--r--src/test/mir-opt/simplify_locals.d2.SimplifyLocals.diff3
-rw-r--r--src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff3
-rw-r--r--src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff1
-rw-r--r--src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff22
-rw-r--r--src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff22
-rw-r--r--src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff78
-rw-r--r--src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff59
-rw-r--r--src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir41
-rw-r--r--src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir21
-rw-r--r--src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir2
-rw-r--r--src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff2
-rw-r--r--src/test/mir-opt/uninhabited_enum_branching2.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir2
-rw-r--r--src/test/mir-opt/uninhabited_enum_branching2.main.UninhabitedEnumBranching.diff2
-rw-r--r--src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir1
-rw-r--r--src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir1
-rw-r--r--src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff1
-rw-r--r--src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff1
-rw-r--r--src/test/run-make/translation/Makefile28
-rw-r--r--src/test/rustdoc-ui/failed-doctest-output-windows.rs28
-rw-r--r--src/test/rustdoc-ui/failed-doctest-output-windows.stdout39
-rw-r--r--src/test/rustdoc-ui/failed-doctest-output.rs3
-rw-r--r--src/test/rustdoc-ui/failed-doctest-output.stdout16
-rw-r--r--src/test/rustdoc/rfc-2632-const-trait-impl.rs31
-rw-r--r--src/test/ui/associated-type-bounds/binder-on-bound.rs11
-rw-r--r--src/test/ui/associated-type-bounds/binder-on-bound.stderr8
-rw-r--r--src/test/ui/block-result/consider-removing-last-semi.stderr6
-rw-r--r--src/test/ui/block-result/issue-11714.stderr2
-rw-r--r--src/test/ui/block-result/issue-13428.stderr2
-rw-r--r--src/test/ui/borrowck/suggest-local-var-for-vector.rs4
-rw-r--r--src/test/ui/borrowck/suggest-local-var-for-vector.stderr24
-rw-r--r--src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs4
-rw-r--r--src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr24
-rw-r--r--src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr22
-rw-r--r--src/test/ui/cast/cast-macro-lhs.rs12
-rw-r--r--src/test/ui/cast/cast-macro-lhs.stderr11
-rw-r--r--src/test/ui/closures/old-closure-expression-remove-semicolon.fixed2
-rw-r--r--src/test/ui/closures/old-closure-expression-remove-semicolon.rs2
-rw-r--r--src/test/ui/closures/old-closure-expression-remove-semicolon.stderr2
-rw-r--r--src/test/ui/coercion/coercion-missing-tail-expected-type.stderr4
-rw-r--r--src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr9
-rw-r--r--src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs2
-rw-r--r--src/test/ui/const-generics/nested-type.min.stderr11
-rw-r--r--src/test/ui/const-generics/nested-type.rs2
-rw-r--r--src/test/ui/consts/const-eval/ub-enum-overwrite.rs17
-rw-r--r--src/test/ui/consts/const-eval/ub-enum-overwrite.stderr20
-rw-r--r--src/test/ui/consts/const-eval/ub-enum.32bit.stderr4
-rw-r--r--src/test/ui/consts/const-eval/ub-enum.64bit.stderr4
-rw-r--r--src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr4
-rw-r--r--src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr4
-rw-r--r--src/test/ui/consts/offset_from_ub.stderr6
-rw-r--r--src/test/ui/consts/std/alloc.32bit.stderr4
-rw-r--r--src/test/ui/consts/std/alloc.64bit.stderr4
-rw-r--r--src/test/ui/error-codes/E0516.stderr5
-rw-r--r--src/test/ui/issues/issue-29184.stderr5
-rw-r--r--src/test/ui/issues/issue-6458-4.stderr2
-rw-r--r--src/test/ui/issues/issue-70093.rs1
-rw-r--r--src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr4
-rw-r--r--src/test/ui/lint/unused/unused-attr-duplicate.rs3
-rw-r--r--src/test/ui/lint/unused/unused-attr-duplicate.stderr101
-rw-r--r--src/test/ui/liveness/liveness-return-last-stmt-semi.stderr2
-rw-r--r--src/test/ui/privacy/restricted/relative-2018.rs2
-rw-r--r--src/test/ui/privacy/restricted/relative-2018.stderr2
-rw-r--r--src/test/ui/ptr_ops/issue-80309-safe.rs2
-rw-r--r--src/test/ui/ptr_ops/issue-80309.rs2
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs102
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr781
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr1
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/feature-gate.rs50
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr236
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs2
-rw-r--r--src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs21
-rw-r--r--src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr45
-rw-r--r--src/test/ui/suggestions/issue-81098.stderr4
-rw-r--r--src/test/ui/suggestions/match-with-different-arm-types-as-stmt-instead-of-expr.stderr2
-rw-r--r--src/test/ui/typeof/type_mismatch.stderr5
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs3
-rw-r--r--src/tools/compiletest/src/header.rs5
253 files changed, 4013 insertions, 1797 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 75ccbc92be1..42ec206fc65 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2483,7 +2483,7 @@ pub struct TraitRef {
 
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct PolyTraitRef {
-    /// The `'a` in `<'a> Foo<&'a T>`.
+    /// The `'a` in `for<'a> Foo<&'a T>`.
     pub bound_generic_params: Vec<GenericParam>,
 
     /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`.
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index 538bfc21290..a7c23dbb79c 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -9,6 +9,8 @@
     test(attr(deny(warnings)))
 )]
 #![feature(box_patterns)]
+#![feature(const_default_impls)]
+#![feature(const_trait_impl)]
 #![feature(crate_visibility_modifier)]
 #![feature(if_let_guard)]
 #![feature(label_break_value)]
diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs
index 70dbda82224..89a0857992e 100644
--- a/compiler/rustc_ast/src/ptr.rs
+++ b/compiler/rustc_ast/src/ptr.rs
@@ -128,14 +128,7 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for P<T> {
 
 impl<T> P<[T]> {
     pub const fn new() -> P<[T]> {
-        // HACK(eddyb) bypass the lack of a `const fn` to create an empty `Box<[T]>`
-        // (as trait methods, `default` in this case, can't be `const fn` yet).
-        P {
-            ptr: unsafe {
-                use std::ptr::NonNull;
-                std::mem::transmute(NonNull::<[T; 0]>::dangling() as NonNull<[T]>)
-            },
-        }
+        P { ptr: Box::default() }
     }
 
     #[inline(never)]
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index a7c600fff78..33727084ccf 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -120,12 +120,21 @@ impl<'a> AstValidator<'a> {
             let err = "`let` expressions are not supported here";
             let mut diag = sess.struct_span_err(expr.span, err);
             diag.note("only supported directly in conditions of `if` and `while` expressions");
-            diag.note("as well as when nested within `&&` and parentheses in those conditions");
-            if let ForbiddenLetReason::ForbiddenWithOr(span) = forbidden_let_reason {
-                diag.span_note(
-                    span,
-                    "`||` operators are not currently supported in let chain expressions",
-                );
+            match forbidden_let_reason {
+                ForbiddenLetReason::GenericForbidden => {}
+                ForbiddenLetReason::NotSupportedOr(span) => {
+                    diag.span_note(
+                        span,
+                        "`||` operators are not supported in let chain expressions",
+                    );
+                }
+                ForbiddenLetReason::NotSupportedParentheses(span) => {
+                    diag.span_note(
+                        span,
+                        "`let`s wrapped in parentheses are not supported in a context with let \
+                        chains",
+                    );
+                }
             }
             diag.emit();
         } else {
@@ -1009,9 +1018,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         self.with_let_management(Some(ForbiddenLetReason::GenericForbidden), |this, forbidden_let_reason| {
             match &expr.kind {
                 ExprKind::Binary(Spanned { node: BinOpKind::Or, span }, lhs, rhs) => {
-                    let forbidden_let_reason = Some(ForbiddenLetReason::ForbiddenWithOr(*span));
-                    this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(lhs));
-                    this.with_let_management(forbidden_let_reason, |this, _| this.visit_expr(rhs));
+                    let local_reason = Some(ForbiddenLetReason::NotSupportedOr(*span));
+                    this.with_let_management(local_reason, |this, _| this.visit_expr(lhs));
+                    this.with_let_management(local_reason, |this, _| this.visit_expr(rhs));
                 }
                 ExprKind::If(cond, then, opt_else) => {
                     this.visit_block(then);
@@ -1036,7 +1045,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         }
                     }
                 }
-                ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
+                ExprKind::Paren(local_expr) => {
+                    fn has_let_expr(expr: &Expr) -> bool {
+                        match expr.kind {
+                            ExprKind::Binary(_, ref lhs, ref rhs) => has_let_expr(lhs) || has_let_expr(rhs),
+                            ExprKind::Let(..) => true,
+                            _ => false,
+                        }
+                    }
+                    let local_reason = if has_let_expr(local_expr) {
+                        Some(ForbiddenLetReason::NotSupportedParentheses(local_expr.span))
+                    }
+                    else {
+                        forbidden_let_reason
+                    };
+                    this.with_let_management(local_reason, |this, _| this.visit_expr(local_expr));
+                }
+                ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
                     this.with_let_management(forbidden_let_reason, |this, _| visit::walk_expr(this, expr));
                     return;
                 }
@@ -1810,8 +1835,13 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
 /// Used to forbid `let` expressions in certain syntactic locations.
 #[derive(Clone, Copy)]
 enum ForbiddenLetReason {
-    /// A let chain with the `||` operator
-    ForbiddenWithOr(Span),
     /// `let` is not valid and the source environment is not important
     GenericForbidden,
+    /// A let chain with the `||` operator
+    NotSupportedOr(Span),
+    /// A let chain with invalid parentheses
+    ///
+    /// For exemple, `let 1 = 1 && (expr && expr)` is allowed
+    /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not
+    NotSupportedParentheses(Span),
 }
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 684eba82667..d38e89cd79e 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -386,6 +386,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
 
             mir::StatementKind::FakeRead(..)
             | mir::StatementKind::SetDiscriminant { .. }
+            | mir::StatementKind::Deinit(..)
             | mir::StatementKind::StorageLive(..)
             | mir::StatementKind::Retag { .. }
             | mir::StatementKind::AscribeUserType(..)
diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs
index eec994f88b9..a5c0d77429d 100644
--- a/compiler/rustc_borrowck/src/def_use.rs
+++ b/compiler/rustc_borrowck/src/def_use.rs
@@ -72,5 +72,9 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
 
         // Debug info is neither def nor use.
         PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None,
+
+        PlaceContext::MutatingUse(MutatingUseContext::Deinit | MutatingUseContext::SetDiscriminant) => {
+            bug!("These statements are not allowed in this MIR phase")
+        }
     }
 }
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index b945d687043..9e5fb674772 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -785,13 +785,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         issued_borrow: &BorrowData<'tcx>,
         explanation: BorrowExplanation,
     ) {
-        let used_in_call =
-            matches!(explanation, BorrowExplanation::UsedLater(LaterUseKind::Call, _call_span, _));
+        let used_in_call = matches!(
+            explanation,
+            BorrowExplanation::UsedLater(LaterUseKind::Call | LaterUseKind::Other, _call_span, _)
+        );
         if !used_in_call {
             debug!("not later used in call");
             return;
         }
 
+        let use_span =
+            if let BorrowExplanation::UsedLater(LaterUseKind::Other, use_span, _) = explanation {
+                Some(use_span)
+            } else {
+                None
+            };
+
         let outer_call_loc =
             if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location {
                 loc
@@ -835,7 +844,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         debug!("===> outer_call_loc = {:?}, inner_call_loc = {:?}", outer_call_loc, inner_call_loc);
 
         let inner_call_span = inner_call_term.source_info.span;
-        let outer_call_span = outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span;
+        let outer_call_span = match use_span {
+            Some(span) => span,
+            None => outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span,
+        };
         if outer_call_span == inner_call_span || !outer_call_span.contains(inner_call_span) {
             // FIXME: This stops the suggestion in some cases where it should be emitted.
             //        Fix the spans for those cases so it's emitted correctly.
@@ -845,8 +857,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             );
             return;
         }
-        err.span_help(inner_call_span, "try adding a local storing this argument...");
-        err.span_help(outer_call_span, "...and then using that local as the argument to this call");
+        err.span_help(
+            inner_call_span,
+            &format!(
+                "try adding a local storing this{}...",
+                if use_span.is_some() { "" } else { " argument" }
+            ),
+        );
+        err.span_help(
+            outer_call_span,
+            &format!(
+                "...and then using that local {}",
+                if use_span.is_some() { "here" } else { "as the argument to this call" }
+            ),
+        );
     }
 
     fn suggest_split_at_mut_if_applicable(
@@ -1912,10 +1936,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         } else {
             "cannot assign twice to immutable variable"
         };
-        if span != assigned_span {
-            if !from_arg {
-                err.span_label(assigned_span, format!("first assignment to {}", place_description));
-            }
+        if span != assigned_span && !from_arg {
+            err.span_label(assigned_span, format!("first assignment to {}", place_description));
         }
         if let Some(decl) = local_decl
             && let Some(name) = local_name
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index 1a789009f06..76d240bb89f 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -63,9 +63,6 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
             StatementKind::FakeRead(box (_, _)) => {
                 // Only relevant for initialized/liveness/safety checks.
             }
-            StatementKind::SetDiscriminant { place, variant_index: _ } => {
-                self.mutate_place(location, **place, Shallow(None));
-            }
             StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
                 ref src,
                 ref dst,
@@ -91,6 +88,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
                     LocalMutationIsAllowed::Yes,
                 );
             }
+            StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+                bug!("Statement not allowed in this MIR phase")
+            }
         }
 
         self.super_statement(statement, location);
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 0a1eae39d75..0c0676f93ad 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -626,9 +626,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
                     flow_state,
                 );
             }
-            StatementKind::SetDiscriminant { place, variant_index: _ } => {
-                self.mutate_place(location, (**place, span), Shallow(None), flow_state);
-            }
             StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
                 ..
             }) => {
@@ -654,6 +651,9 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
                     flow_state,
                 );
             }
+            StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+                bug!("Statement not allowed in this MIR phase")
+            }
         }
     }
 
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index e9fa33f656f..ece801716b2 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1303,28 +1303,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     );
                 }
             }
-            StatementKind::SetDiscriminant { ref place, variant_index } => {
-                let place_type = place.ty(body, tcx).ty;
-                let adt = match place_type.kind() {
-                    ty::Adt(adt, _) if adt.is_enum() => adt,
-                    _ => {
-                        span_bug!(
-                            stmt.source_info.span,
-                            "bad set discriminant ({:?} = {:?}): lhs is not an enum",
-                            place,
-                            variant_index
-                        );
-                    }
-                };
-                if variant_index.as_usize() >= adt.variants().len() {
-                    span_bug!(
-                        stmt.source_info.span,
-                        "bad set discriminant ({:?} = {:?}): value of of range",
-                        place,
-                        variant_index
-                    );
-                };
-            }
             StatementKind::AscribeUserType(box (ref place, ref projection), variance) => {
                 let place_ty = place.ty(body, tcx).ty;
                 if let Err(terr) = self.relate_type_and_user_type(
@@ -1358,6 +1336,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             | StatementKind::Retag { .. }
             | StatementKind::Coverage(..)
             | StatementKind::Nop => {}
+            StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => {
+                bug!("Statement not allowed in this MIR phase")
+            }
         }
     }
 
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index a9ff710c91e..8c45993a8b7 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -772,6 +772,7 @@ fn codegen_stmt<'tcx>(
         }
         StatementKind::StorageLive(_)
         | StatementKind::StorageDead(_)
+        | StatementKind::Deinit(_)
         | StatementKind::Nop
         | StatementKind::FakeRead(..)
         | StatementKind::Retag { .. }
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 4657791345b..57074f00210 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -518,6 +518,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
                         StatementKind::Assign(_)
                         | StatementKind::FakeRead(_)
                         | StatementKind::SetDiscriminant { .. }
+                        | StatementKind::Deinit(_)
                         | StatementKind::StorageLive(_)
                         | StatementKind::StorageDead(_)
                         | StatementKind::Retag(_, _)
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 03c390b4bd4..91d132eb343 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -290,6 +290,11 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
         }
         attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs });
 
+        // Switch to the 'normal' basic block if we did an `invoke` instead of a `call`
+        if let Some((dest, _, _)) = dest_catch_funclet {
+            self.switch_to_block(dest);
+        }
+
         // Write results to outputs
         for (idx, op) in operands.iter().enumerate() {
             if let InlineAsmOperandRef::Out { reg, place: Some(place), .. }
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index d768d4920c5..efb424af3ed 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -211,6 +211,8 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
 
             PlaceContext::MutatingUse(
                 MutatingUseContext::Store
+                | MutatingUseContext::Deinit
+                | MutatingUseContext::SetDiscriminant
                 | MutatingUseContext::AsmOutput
                 | MutatingUseContext::Borrow
                 | MutatingUseContext::AddressOf
diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs
index 773dc2adcfa..d9ebfc3e871 100644
--- a/compiler/rustc_codegen_ssa/src/mir/statement.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs
@@ -48,6 +48,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     .codegen_set_discr(&mut bx, variant_index);
                 bx
             }
+            mir::StatementKind::Deinit(..) => {
+                // For now, don't codegen this to anything. In the future it may be worth
+                // experimenting with what kind of information we can emit to LLVM without hurting
+                // perf here
+                bx
+            }
             mir::StatementKind::StorageLive(local) => {
                 if let LocalRef::Place(cg_place) = self.locals[local] {
                     cg_place.storage_live(&mut bx);
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 556a44a5238..a165fa23f30 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -890,6 +890,11 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> {
     ) -> InterpResult<'tcx> {
         self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size), val)
     }
+
+    /// Mark the entire referenced range as uninitalized
+    pub fn write_uninit(&mut self) {
+        self.alloc.mark_init(self.range, false);
+    }
 }
 
 impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 51d47af2f8e..8dc74035d61 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -791,6 +791,42 @@ where
         }
     }
 
+    pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
+        let mplace = match dest.place {
+            Place::Ptr(mplace) => MPlaceTy { mplace, layout: dest.layout },
+            Place::Local { frame, local } => {
+                match M::access_local_mut(self, frame, local)? {
+                    Ok(local) => match dest.layout.abi {
+                        Abi::Scalar(_) => {
+                            *local = LocalValue::Live(Operand::Immediate(Immediate::Scalar(
+                                ScalarMaybeUninit::Uninit,
+                            )));
+                            return Ok(());
+                        }
+                        Abi::ScalarPair(..) => {
+                            *local = LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(
+                                ScalarMaybeUninit::Uninit,
+                                ScalarMaybeUninit::Uninit,
+                            )));
+                            return Ok(());
+                        }
+                        _ => self.force_allocation(dest)?,
+                    },
+                    Err(mplace) => {
+                        // The local is in memory, go on below.
+                        MPlaceTy { mplace, layout: dest.layout }
+                    }
+                }
+            }
+        };
+        let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else {
+            // Zero-sized access
+            return Ok(());
+        };
+        alloc.write_uninit();
+        Ok(())
+    }
+
     /// Copies the data from an operand to a place. This does not support transmuting!
     /// Use `copy_op_transmute` if the layouts could disagree.
     #[inline(always)]
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 84563daa088..eb1a184bf9b 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -90,6 +90,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 self.write_discriminant(*variant_index, &dest)?;
             }
 
+            Deinit(place) => {
+                let dest = self.eval_place(**place)?;
+                self.write_uninit(&dest)?;
+            }
+
             // Mark locals as alive
             StorageLive(local) => {
                 self.storage_live(*local)?;
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 625f57b872b..7e2a50444db 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -692,6 +692,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
         match statement.kind {
             StatementKind::Assign(..)
             | StatementKind::SetDiscriminant { .. }
+            | StatementKind::Deinit(..)
             | StatementKind::FakeRead(..)
             | StatementKind::StorageLive(_)
             | StatementKind::StorageDead(_)
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 263959f3cb3..01af9585135 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -3,15 +3,14 @@
 use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::interpret::Scalar;
-use rustc_middle::mir::traversal;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{
-    AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPass, MirPhase, Operand,
-    PlaceElem, PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator,
-    TerminatorKind, START_BLOCK,
+    traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, Local, Location, MirPass,
+    MirPhase, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement,
+    StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK,
 };
 use rustc_middle::ty::fold::BottomUpFolder;
-use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable};
 use rustc_mir_dataflow::impls::MaybeStorageLive;
 use rustc_mir_dataflow::storage::AlwaysLiveLocals;
 use rustc_mir_dataflow::{Analysis, ResultsCursor};
@@ -36,6 +35,13 @@ pub struct Validator {
 
 impl<'tcx> MirPass<'tcx> for Validator {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        // FIXME(JakobDegen): These bodies never instantiated in codegend anyway, so it's not
+        // terribly important that they pass the validator. However, I think other passes might
+        // still see them, in which case they might be surprised. It would probably be better if we
+        // didn't put this through the MIR pipeline at all.
+        if matches!(body.source.instance, InstanceDef::Intrinsic(..) | InstanceDef::Virtual(..)) {
+            return;
+        }
         let def_id = body.source.def_id();
         let param_env = tcx.param_env(def_id);
         let mir_phase = self.mir_phase;
@@ -240,58 +246,179 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
         self.super_projection_elem(local, proj_base, elem, context, location);
     }
 
-    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
-        match &statement.kind {
-            StatementKind::Assign(box (dest, rvalue)) => {
-                // LHS and RHS of the assignment must have the same type.
-                let left_ty = dest.ty(&self.body.local_decls, self.tcx).ty;
-                let right_ty = rvalue.ty(&self.body.local_decls, self.tcx);
-                if !self.mir_assign_valid_types(right_ty, left_ty) {
+    fn visit_place(&mut self, place: &Place<'tcx>, _: PlaceContext, _: Location) {
+        // Set off any `bug!`s in the type computation code
+        let _ = place.ty(&self.body.local_decls, self.tcx);
+    }
+
+    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
+        macro_rules! check_kinds {
+            ($t:expr, $text:literal, $($patterns:tt)*) => {
+                if !matches!(($t).kind(), $($patterns)*) {
+                    self.fail(location, format!($text, $t));
+                }
+            };
+        }
+        match rvalue {
+            Rvalue::Use(_) => {}
+            Rvalue::Aggregate(agg_kind, _) => {
+                let disallowed = match **agg_kind {
+                    AggregateKind::Array(..) => false,
+                    AggregateKind::Generator(..) => self.mir_phase >= MirPhase::GeneratorsLowered,
+                    _ => self.mir_phase >= MirPhase::Deaggregated,
+                };
+                if disallowed {
                     self.fail(
                         location,
-                        format!(
-                            "encountered `{:?}` with incompatible types:\n\
-                            left-hand side has type: {}\n\
-                            right-hand side has type: {}",
-                            statement.kind, left_ty, right_ty,
-                        ),
+                        format!("{:?} have been lowered to field assignments", rvalue),
+                    )
+                }
+            }
+            Rvalue::Ref(_, BorrowKind::Shallow, _) => {
+                if self.mir_phase >= MirPhase::DropsLowered {
+                    self.fail(
+                        location,
+                        "`Assign` statement with a `Shallow` borrow should have been removed after drop lowering phase",
                     );
                 }
-                match rvalue {
-                    // The sides of an assignment must not alias. Currently this just checks whether the places
-                    // are identical.
-                    Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => {
-                        if dest == src {
+            }
+            Rvalue::Len(p) => {
+                let pty = p.ty(&self.body.local_decls, self.tcx).ty;
+                check_kinds!(
+                    pty,
+                    "Cannot compute length of non-array type {:?}",
+                    ty::Array(..) | ty::Slice(..)
+                );
+            }
+            Rvalue::BinaryOp(op, vals) | Rvalue::CheckedBinaryOp(op, vals) => {
+                use BinOp::*;
+                let a = vals.0.ty(&self.body.local_decls, self.tcx);
+                let b = vals.1.ty(&self.body.local_decls, self.tcx);
+                match op {
+                    Offset => {
+                        check_kinds!(a, "Cannot offset non-pointer type {:?}", ty::RawPtr(..));
+                        if b != self.tcx.types.isize && b != self.tcx.types.usize {
+                            self.fail(location, format!("Cannot offset by non-isize type {:?}", b));
+                        }
+                    }
+                    Eq | Lt | Le | Ne | Ge | Gt => {
+                        for x in [a, b] {
+                            check_kinds!(
+                                x,
+                                "Cannot compare type {:?}",
+                                ty::Bool
+                                    | ty::Char
+                                    | ty::Int(..)
+                                    | ty::Uint(..)
+                                    | ty::Float(..)
+                                    | ty::RawPtr(..)
+                                    | ty::FnPtr(..)
+                            )
+                        }
+                        // None of the possible types have lifetimes, so we can just compare
+                        // directly
+                        if a != b {
                             self.fail(
                                 location,
-                                "encountered `Assign` statement with overlapping memory",
+                                format!("Cannot compare unequal types {:?} and {:?}", a, b),
                             );
                         }
                     }
-                    Rvalue::Aggregate(agg_kind, _) => {
-                        let disallowed = match **agg_kind {
-                            AggregateKind::Array(..) => false,
-                            AggregateKind::Generator(..) => {
-                                self.mir_phase >= MirPhase::GeneratorsLowered
-                            }
-                            _ => self.mir_phase >= MirPhase::Deaggregated,
-                        };
-                        if disallowed {
+                    Shl | Shr => {
+                        for x in [a, b] {
+                            check_kinds!(
+                                x,
+                                "Cannot shift non-integer type {:?}",
+                                ty::Uint(..) | ty::Int(..)
+                            )
+                        }
+                    }
+                    BitAnd | BitOr | BitXor => {
+                        for x in [a, b] {
+                            check_kinds!(
+                                x,
+                                "Cannot perform bitwise op on type {:?}",
+                                ty::Uint(..) | ty::Int(..) | ty::Bool
+                            )
+                        }
+                        if a != b {
                             self.fail(
                                 location,
-                                format!("{:?} have been lowered to field assignments", rvalue),
-                            )
+                                format!(
+                                    "Cannot perform bitwise op on unequal types {:?} and {:?}",
+                                    a, b
+                                ),
+                            );
                         }
                     }
-                    Rvalue::Ref(_, BorrowKind::Shallow, _) => {
-                        if self.mir_phase >= MirPhase::DropsLowered {
+                    Add | Sub | Mul | Div | Rem => {
+                        for x in [a, b] {
+                            check_kinds!(
+                                x,
+                                "Cannot perform op on type {:?}",
+                                ty::Uint(..) | ty::Int(..) | ty::Float(..)
+                            )
+                        }
+                        if a != b {
                             self.fail(
                                 location,
-                                "`Assign` statement with a `Shallow` borrow should have been removed after drop lowering phase",
+                                format!("Cannot perform op on unequal types {:?} and {:?}", a, b),
                             );
                         }
                     }
-                    _ => {}
+                }
+            }
+            Rvalue::UnaryOp(op, operand) => {
+                let a = operand.ty(&self.body.local_decls, self.tcx);
+                match op {
+                    UnOp::Neg => {
+                        check_kinds!(a, "Cannot negate type {:?}", ty::Int(..) | ty::Float(..))
+                    }
+                    UnOp::Not => {
+                        check_kinds!(
+                            a,
+                            "Cannot binary not type {:?}",
+                            ty::Int(..) | ty::Uint(..) | ty::Bool
+                        );
+                    }
+                }
+            }
+            Rvalue::ShallowInitBox(operand, _) => {
+                let a = operand.ty(&self.body.local_decls, self.tcx);
+                check_kinds!(a, "Cannot shallow init type {:?}", ty::RawPtr(..));
+            }
+            _ => {}
+        }
+        self.super_rvalue(rvalue, location);
+    }
+
+    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
+        match &statement.kind {
+            StatementKind::Assign(box (dest, rvalue)) => {
+                // LHS and RHS of the assignment must have the same type.
+                let left_ty = dest.ty(&self.body.local_decls, self.tcx).ty;
+                let right_ty = rvalue.ty(&self.body.local_decls, self.tcx);
+                if !self.mir_assign_valid_types(right_ty, left_ty) {
+                    self.fail(
+                        location,
+                        format!(
+                            "encountered `{:?}` with incompatible types:\n\
+                            left-hand side has type: {}\n\
+                            right-hand side has type: {}",
+                            statement.kind, left_ty, right_ty,
+                        ),
+                    );
+                }
+                // FIXME(JakobDegen): Check this for all rvalues, not just this one.
+                if let Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) = rvalue {
+                    // The sides of an assignment must not alias. Currently this just checks whether
+                    // the places are identical.
+                    if dest == src {
+                        self.fail(
+                            location,
+                            "encountered `Assign` statement with overlapping memory",
+                        );
+                    }
                 }
             }
             StatementKind::AscribeUserType(..) => {
@@ -346,9 +473,24 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     self.fail(location, format!("bad arg ({:?} != usize)", op_cnt_ty))
                 }
             }
-            StatementKind::SetDiscriminant { .. } => {
-                if self.mir_phase < MirPhase::DropsLowered {
-                    self.fail(location, "`SetDiscriminant` is not allowed until drop elaboration");
+            StatementKind::SetDiscriminant { place, .. } => {
+                if self.mir_phase < MirPhase::Deaggregated {
+                    self.fail(location, "`SetDiscriminant`is not allowed until deaggregation");
+                }
+                let pty = place.ty(&self.body.local_decls, self.tcx).ty.kind();
+                if !matches!(pty, ty::Adt(..) | ty::Generator(..) | ty::Opaque(..)) {
+                    self.fail(
+                        location,
+                        format!(
+                            "`SetDiscriminant` is only allowed on ADTs and generators, not {:?}",
+                            pty
+                        ),
+                    );
+                }
+            }
+            StatementKind::Deinit(..) => {
+                if self.mir_phase < MirPhase::Deaggregated {
+                    self.fail(location, "`Deinit`is not allowed until deaggregation");
                 }
             }
             StatementKind::Retag(_, _) => {
@@ -497,6 +639,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                 }
             }
             TerminatorKind::Yield { resume, drop, .. } => {
+                if self.body.generator.is_none() {
+                    self.fail(location, "`Yield` cannot appear outside generator bodies");
+                }
                 if self.mir_phase >= MirPhase::GeneratorsLowered {
                     self.fail(location, "`Yield` should have been replaced by generator lowering");
                 }
@@ -536,6 +681,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                 }
             }
             TerminatorKind::GeneratorDrop => {
+                if self.body.generator.is_none() {
+                    self.fail(location, "`GeneratorDrop` cannot appear outside generator bodies");
+                }
                 if self.mir_phase >= MirPhase::GeneratorsLowered {
                     self.fail(
                         location,
@@ -543,11 +691,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     );
                 }
             }
-            // Nothing to validate for these.
-            TerminatorKind::Resume
-            | TerminatorKind::Abort
-            | TerminatorKind::Return
-            | TerminatorKind::Unreachable => {}
+            TerminatorKind::Resume | TerminatorKind::Abort => {
+                let bb = location.block;
+                if !self.body.basic_blocks()[bb].is_cleanup {
+                    self.fail(location, "Cannot `Resume` or `Abort` from non-cleanup basic block")
+                }
+            }
+            TerminatorKind::Return => {
+                let bb = location.block;
+                if self.body.basic_blocks()[bb].is_cleanup {
+                    self.fail(location, "Cannot `Return` from cleanup basic block")
+                }
+            }
+            TerminatorKind::Unreachable => {}
         }
 
         self.super_terminator(terminator, location);
diff --git a/compiler/rustc_const_eval/src/util/aggregate.rs b/compiler/rustc_const_eval/src/util/aggregate.rs
index e5f5e7072d5..180a40043db 100644
--- a/compiler/rustc_const_eval/src/util/aggregate.rs
+++ b/compiler/rustc_const_eval/src/util/aggregate.rs
@@ -14,22 +14,26 @@ use std::iter::TrustedLen;
 /// (lhs as Variant).field1 = arg1;
 /// discriminant(lhs) = variant_index;  // If lhs is an enum or generator.
 pub fn expand_aggregate<'tcx>(
-    mut lhs: Place<'tcx>,
+    orig_lhs: Place<'tcx>,
     operands: impl Iterator<Item = (Operand<'tcx>, Ty<'tcx>)> + TrustedLen,
     kind: AggregateKind<'tcx>,
     source_info: SourceInfo,
     tcx: TyCtxt<'tcx>,
 ) -> impl Iterator<Item = Statement<'tcx>> + TrustedLen {
+    let mut lhs = orig_lhs;
     let mut set_discriminant = None;
     let active_field_index = match kind {
         AggregateKind::Adt(adt_did, variant_index, _, _, active_field_index) => {
             let adt_def = tcx.adt_def(adt_did);
             if adt_def.is_enum() {
                 set_discriminant = Some(Statement {
-                    kind: StatementKind::SetDiscriminant { place: Box::new(lhs), variant_index },
+                    kind: StatementKind::SetDiscriminant {
+                        place: Box::new(orig_lhs),
+                        variant_index,
+                    },
                     source_info,
                 });
-                lhs = tcx.mk_place_downcast(lhs, adt_def, variant_index);
+                lhs = tcx.mk_place_downcast(orig_lhs, adt_def, variant_index);
             }
             active_field_index
         }
@@ -38,7 +42,7 @@ pub fn expand_aggregate<'tcx>(
             // variant 0 (Unresumed).
             let variant_index = VariantIdx::new(0);
             set_discriminant = Some(Statement {
-                kind: StatementKind::SetDiscriminant { place: Box::new(lhs), variant_index },
+                kind: StatementKind::SetDiscriminant { place: Box::new(orig_lhs), variant_index },
                 source_info,
             });
 
@@ -50,27 +54,24 @@ pub fn expand_aggregate<'tcx>(
         _ => None,
     };
 
-    operands
-        .enumerate()
-        .map(move |(i, (op, ty))| {
-            let lhs_field = if let AggregateKind::Array(_) = kind {
-                let offset = u64::try_from(i).unwrap();
-                tcx.mk_place_elem(
-                    lhs,
-                    ProjectionElem::ConstantIndex {
-                        offset,
-                        min_length: offset + 1,
-                        from_end: false,
-                    },
-                )
-            } else {
-                let field = Field::new(active_field_index.unwrap_or(i));
-                tcx.mk_place_field(lhs, field, ty)
-            };
-            Statement {
-                source_info,
-                kind: StatementKind::Assign(Box::new((lhs_field, Rvalue::Use(op)))),
-            }
-        })
+    let operands = operands.enumerate().map(move |(i, (op, ty))| {
+        let lhs_field = if let AggregateKind::Array(_) = kind {
+            let offset = u64::try_from(i).unwrap();
+            tcx.mk_place_elem(
+                lhs,
+                ProjectionElem::ConstantIndex { offset, min_length: offset + 1, from_end: false },
+            )
+        } else {
+            let field = Field::new(active_field_index.unwrap_or(i));
+            tcx.mk_place_field(lhs, field, ty)
+        };
+        Statement {
+            source_info,
+            kind: StatementKind::Assign(Box::new((lhs_field, Rvalue::Use(op)))),
+        }
+    });
+    [Statement { source_info, kind: StatementKind::Deinit(Box::new(orig_lhs)) }]
+        .into_iter()
+        .chain(operands)
         .chain(set_discriminant)
 }
diff --git a/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl b/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl
index 336e7a66857..2b1deb34304 100644
--- a/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl
@@ -62,6 +62,7 @@ typeck-functional-record-update-on-non-struct =
 
 typeck-typeof-reserved-keyword-used =
     `typeof` is a reserved keyword but unimplemented
+    .suggestion = consider replacing `typeof(...)` with an actual type
     .label = reserved keyword
 
 typeck-return-stmt-outside-of-fn-body =
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 88f3b547605..b33e6b66117 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -11,7 +11,7 @@ use std::error::Error;
 use std::fmt;
 use std::fs;
 use std::io;
-use std::path::Path;
+use std::path::{Path, PathBuf};
 use tracing::{instrument, trace};
 
 #[cfg(parallel_compiler)]
@@ -45,7 +45,7 @@ pub enum TranslationBundleError {
     /// Failed to add `FluentResource` to `FluentBundle`.
     AddResource(FluentError),
     /// `$sysroot/share/locale/$locale` does not exist.
-    MissingLocale(io::Error),
+    MissingLocale,
     /// Cannot read directory entries of `$sysroot/share/locale/$locale`.
     ReadLocalesDir(io::Error),
     /// Cannot read directory entry of `$sysroot/share/locale/$locale`.
@@ -62,9 +62,7 @@ impl fmt::Display for TranslationBundleError {
                 write!(f, "could not parse ftl file: {}", e)
             }
             TranslationBundleError::AddResource(e) => write!(f, "failed to add resource: {}", e),
-            TranslationBundleError::MissingLocale(e) => {
-                write!(f, "missing locale directory: {}", e)
-            }
+            TranslationBundleError::MissingLocale => write!(f, "missing locale directory"),
             TranslationBundleError::ReadLocalesDir(e) => {
                 write!(f, "could not read locales dir: {}", e)
             }
@@ -84,7 +82,7 @@ impl Error for TranslationBundleError {
             TranslationBundleError::ReadFtl(e) => Some(e),
             TranslationBundleError::ParseFtl(e) => Some(e),
             TranslationBundleError::AddResource(e) => Some(e),
-            TranslationBundleError::MissingLocale(e) => Some(e),
+            TranslationBundleError::MissingLocale => None,
             TranslationBundleError::ReadLocalesDir(e) => Some(e),
             TranslationBundleError::ReadLocalesDirEntry(e) => Some(e),
             TranslationBundleError::LocaleIsNotDir => None,
@@ -113,7 +111,8 @@ impl From<Vec<FluentError>> for TranslationBundleError {
 /// (overriding any conflicting messages).
 #[instrument(level = "trace")]
 pub fn fluent_bundle(
-    sysroot: &Path,
+    mut user_provided_sysroot: Option<PathBuf>,
+    mut sysroot_candidates: Vec<PathBuf>,
     requested_locale: Option<LanguageIdentifier>,
     additional_ftl_path: Option<&Path>,
     with_directionality_markers: bool,
@@ -140,33 +139,43 @@ pub fn fluent_bundle(
 
     // If the user requests the default locale then don't try to load anything.
     if !requested_fallback_locale && let Some(requested_locale) = requested_locale {
-        let mut sysroot = sysroot.to_path_buf();
-        sysroot.push("share");
-        sysroot.push("locale");
-        sysroot.push(requested_locale.to_string());
-        trace!(?sysroot);
-
-        let _ = sysroot.try_exists().map_err(TranslationBundleError::MissingLocale)?;
-
-        if !sysroot.is_dir() {
-            return Err(TranslationBundleError::LocaleIsNotDir);
-        }
-
-        for entry in sysroot.read_dir().map_err(TranslationBundleError::ReadLocalesDir)? {
-            let entry = entry.map_err(TranslationBundleError::ReadLocalesDirEntry)?;
-            let path = entry.path();
-            trace!(?path);
-            if path.extension().and_then(|s| s.to_str()) != Some("ftl") {
+        let mut found_resources = false;
+        for sysroot in user_provided_sysroot.iter_mut().chain(sysroot_candidates.iter_mut()) {
+            sysroot.push("share");
+            sysroot.push("locale");
+            sysroot.push(requested_locale.to_string());
+            trace!(?sysroot);
+
+            if !sysroot.exists() {
                 trace!("skipping");
                 continue;
             }
 
-            let resource_str =
-                fs::read_to_string(path).map_err(TranslationBundleError::ReadFtl)?;
-            let resource =
-                FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?;
-            trace!(?resource);
-            bundle.add_resource(resource).map_err(TranslationBundleError::from)?;
+            if !sysroot.is_dir() {
+                return Err(TranslationBundleError::LocaleIsNotDir);
+            }
+
+            for entry in sysroot.read_dir().map_err(TranslationBundleError::ReadLocalesDir)? {
+                let entry = entry.map_err(TranslationBundleError::ReadLocalesDirEntry)?;
+                let path = entry.path();
+                trace!(?path);
+                if path.extension().and_then(|s| s.to_str()) != Some("ftl") {
+                    trace!("skipping");
+                    continue;
+                }
+
+                let resource_str =
+                    fs::read_to_string(path).map_err(TranslationBundleError::ReadFtl)?;
+                let resource =
+                    FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?;
+                trace!(?resource);
+                bundle.add_resource(resource).map_err(TranslationBundleError::from)?;
+                found_resources = true;
+            }
+        }
+
+        if !found_resources {
+            return Err(TranslationBundleError::MissingLocale);
         }
     }
 
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index ce243b4a672..b5f56d7d6dc 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -81,22 +81,12 @@ use rustc_session::parse::ParseSess;
 use rustc_span::symbol::MacroRulesNormalizedIdent;
 use rustc_span::Span;
 
-use smallvec::{smallvec, SmallVec};
-
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
 use rustc_span::symbol::Ident;
 use std::borrow::Cow;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 
-// One element is enough to cover 95-99% of vectors for most benchmarks. Also, vectors longer than
-// one frequently have many elements, not just two or three.
-type NamedMatchVec = SmallVec<[NamedMatch; 1]>;
-
-// This type is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(NamedMatchVec, 48);
-
 /// A unit within a matcher that a `MatcherPos` can refer to. Similar to (and derived from)
 /// `mbe::TokenTree`, but designed specifically for fast and easy traversal during matching.
 /// Notable differences to `mbe::TokenTree`:
@@ -221,7 +211,11 @@ struct MatcherPos {
     /// with one element per metavar decl in the matcher. Each element records token trees matched
     /// against the relevant metavar by the black box parser. An element will be a `MatchedSeq` if
     /// the corresponding metavar decl is within a sequence.
-    matches: Lrc<NamedMatchVec>,
+    ///
+    /// It is critical to performance that this is an `Lrc`, because it gets cloned frequently when
+    /// processing sequences. Mostly for sequence-ending possibilities that must be tried but end
+    /// up failing.
+    matches: Lrc<Vec<NamedMatch>>,
 }
 
 // This type is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -246,18 +240,12 @@ impl MatcherPos {
                 let mut curr = &mut matches[metavar_idx];
                 for _ in 0..seq_depth - 1 {
                     match curr {
-                        MatchedSeq(seq) => {
-                            let seq = Lrc::make_mut(seq);
-                            curr = seq.last_mut().unwrap();
-                        }
+                        MatchedSeq(seq) => curr = seq.last_mut().unwrap(),
                         _ => unreachable!(),
                     }
                 }
                 match curr {
-                    MatchedSeq(seq) => {
-                        let seq = Lrc::make_mut(seq);
-                        seq.push(m);
-                    }
+                    MatchedSeq(seq) => seq.push(m),
                     _ => unreachable!(),
                 }
             }
@@ -350,7 +338,7 @@ pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
 /// ```
 #[derive(Debug, Clone)]
 crate enum NamedMatch {
-    MatchedSeq(Lrc<NamedMatchVec>),
+    MatchedSeq(Vec<NamedMatch>),
 
     // A metavar match of type `tt`.
     MatchedTokenTree(rustc_ast::tokenstream::TokenTree),
@@ -388,7 +376,7 @@ pub struct TtParser {
 
     /// Pre-allocate an empty match array, so it can be cloned cheaply for macros with many rules
     /// that have no metavars.
-    empty_matches: Lrc<NamedMatchVec>,
+    empty_matches: Lrc<Vec<NamedMatch>>,
 }
 
 impl TtParser {
@@ -398,7 +386,7 @@ impl TtParser {
             cur_mps: vec![],
             next_mps: vec![],
             bb_mps: vec![],
-            empty_matches: Lrc::new(smallvec![]),
+            empty_matches: Lrc::new(vec![]),
         }
     }
 
@@ -452,11 +440,7 @@ impl TtParser {
                 } => {
                     // Install an empty vec for each metavar within the sequence.
                     for metavar_idx in next_metavar..next_metavar + num_metavar_decls {
-                        mp.push_match(
-                            metavar_idx,
-                            seq_depth,
-                            MatchedSeq(self.empty_matches.clone()),
-                        );
+                        mp.push_match(metavar_idx, seq_depth, MatchedSeq(vec![]));
                     }
 
                     if op == KleeneOp::ZeroOrMore || op == KleeneOp::ZeroOrOne {
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 31dae6a2fb4..f5c7186bc4b 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -439,7 +439,8 @@ pub fn compile_declarative_macro(
     let argument_gram = mbe::macro_parser::compute_locs(&sess.parse_sess, &argument_gram);
 
     let parser = Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS);
-    let mut tt_parser = TtParser::new(def.ident);
+    let mut tt_parser =
+        TtParser::new(Ident::with_dummy_span(if macro_rules { kw::MacroRules } else { kw::Macro }));
     let argument_map = match tt_parser.parse_tt(&mut Cow::Borrowed(&parser), &argument_gram) {
         Success(m) => m,
         Failure(token, msg) => {
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 7c53f839a92..e588385cfca 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -310,7 +310,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
 
     // Crate properties:
     ungated!(crate_name, CrateLevel, template!(NameValueStr: "name"), FutureWarnFollowing),
-    ungated!(crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), FutureWarnFollowing),
+    ungated!(crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), DuplicatesOk),
     // crate_id is deprecated
     ungated!(crate_id, CrateLevel, template!(NameValueStr: "ignored"), FutureWarnFollowing),
 
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index a3570320767..fe75ee8b37b 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -44,6 +44,7 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
     let sess = build_session(
         sessopts,
         None,
+        None,
         registry,
         DiagnosticOutput::Default,
         Default::default(),
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 592cf60e6c3..3fa8017dc93 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -83,9 +83,23 @@ pub fn create_session(
     // target_override is documented to be called before init(), so this is okay
     let target_override = codegen_backend.target_override(&sopts);
 
+    let bundle = match rustc_errors::fluent_bundle(
+        sopts.maybe_sysroot.clone(),
+        sysroot_candidates(),
+        sopts.debugging_opts.translate_lang.clone(),
+        sopts.debugging_opts.translate_additional_ftl.as_deref(),
+        sopts.debugging_opts.translate_directionality_markers,
+    ) {
+        Ok(bundle) => bundle,
+        Err(e) => {
+            early_error(sopts.error_format, &format!("failed to load fluent bundle: {e}"));
+        }
+    };
+
     let mut sess = session::build_session(
         sopts,
         input_path,
+        bundle,
         descriptions,
         diagnostic_output,
         lint_caps,
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 7030fd53704..71f21dc6666 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -995,6 +995,13 @@ LLVMRustOptimizeWithNewPassManager(
         break;
       }
     }
+  } else {
+    // We're not building any of the default pipelines but we still want to
+    // add the verifier, instrumentation, etc passes if they were requested
+    for (const auto &C : PipelineStartEPCallbacks)
+      C(MPM, OptLevel);
+    for (const auto &C : OptimizerLastEPCallbacks)
+      C(MPM, OptLevel);
   }
 
   if (ExtraPassesLen) {
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 06658aadbac..aebd293f6c2 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -5,7 +5,9 @@
 #![feature(nll)]
 #![feature(once_cell)]
 #![feature(proc_macro_internals)]
+#![feature(macro_metavar_expr)]
 #![feature(min_specialization)]
+#![feature(slice_as_chunks)]
 #![feature(try_blocks)]
 #![feature(never_type)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 3402acccf3f..3933a0d19a4 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -292,6 +292,18 @@ trait LazyQueryDecodable<'a, 'tcx, T> {
     ) -> T;
 }
 
+impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, T> for T {
+    fn decode_query(self, _: CrateMetadataRef<'a>, _: TyCtxt<'tcx>, _: impl FnOnce() -> !) -> T {
+        self
+    }
+}
+
+impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, T> for Option<T> {
+    fn decode_query(self, _: CrateMetadataRef<'a>, _: TyCtxt<'tcx>, err: impl FnOnce() -> !) -> T {
+        if let Some(l) = self { l } else { err() }
+    }
+}
+
 impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, T> for Option<Lazy<T>>
 where
     T: Decodable<DecodeContext<'a, 'tcx>>,
@@ -376,6 +388,17 @@ impl<'a, 'tcx> LazyQueryDecodable<'a, 'tcx, Option<DeprecationEntry>>
     }
 }
 
+impl<'a, 'tcx> LazyQueryDecodable<'a, 'tcx, Option<DefId>> for Option<RawDefId> {
+    fn decode_query(
+        self,
+        cdata: CrateMetadataRef<'a>,
+        _: TyCtxt<'tcx>,
+        _: impl FnOnce() -> !,
+    ) -> Option<DefId> {
+        self.map(|raw_def_id| raw_def_id.decode(cdata))
+    }
+}
+
 impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
     #[inline]
     fn tcx(&self) -> TyCtxt<'tcx> {
@@ -394,8 +417,9 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
         self.cdata.unwrap()
     }
 
+    #[inline]
     fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum {
-        if cnum == LOCAL_CRATE { self.cdata().cnum } else { self.cdata().cnum_map[cnum] }
+        self.cdata().map_encoded_cnum_to_current(cnum)
     }
 
     fn read_lazy_with_meta<T: ?Sized + LazyMeta>(&mut self, meta: T::Meta) -> Lazy<T> {
@@ -706,8 +730,7 @@ impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a
     }
 }
 
-impl<'a, 'tcx, I: Idx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a, 'tcx>>
-    for Lazy<Table<I, T>>
+impl<'a, 'tcx, I: Idx, T> Decodable<DecodeContext<'a, 'tcx>> for Lazy<Table<I, T>>
 where
     Option<T>: FixedSizeEncoding,
 {
@@ -844,6 +867,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         self.root.tables.kind.get(self, item_id).map(|k| k.decode(self))
     }
 
+    #[inline]
+    pub(super) fn map_encoded_cnum_to_current(self, cnum: CrateNum) -> CrateNum {
+        if cnum == LOCAL_CRATE { self.cnum } else { self.cnum_map[cnum] }
+    }
+
     fn kind(self, item_id: DefIndex) -> EntryKind {
         self.maybe_kind(item_id).unwrap_or_else(|| {
             bug!(
@@ -856,16 +884,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
     }
 
     fn def_kind(self, item_id: DefIndex) -> DefKind {
-        self.root.tables.opt_def_kind.get(self, item_id).map(|k| k.decode(self)).unwrap_or_else(
-            || {
-                bug!(
-                    "CrateMetadata::def_kind({:?}): id not found, in crate {:?} with number {}",
-                    item_id,
-                    self.root.name,
-                    self.cnum,
-                )
-            },
-        )
+        self.root.tables.opt_def_kind.get(self, item_id).unwrap_or_else(|| {
+            bug!(
+                "CrateMetadata::def_kind({:?}): id not found, in crate {:?} with number {}",
+                item_id,
+                self.root.name,
+                self.cnum,
+            )
+        })
     }
 
     fn get_span(self, index: DefIndex, sess: &Session) -> Span {
@@ -1449,9 +1475,9 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         index: DefIndex,
         def_path_hashes: &mut FxHashMap<DefIndex, DefPathHash>,
     ) -> DefPathHash {
-        *def_path_hashes.entry(index).or_insert_with(|| {
-            self.root.tables.def_path_hashes.get(self, index).unwrap().decode(self)
-        })
+        *def_path_hashes
+            .entry(index)
+            .or_insert_with(|| self.root.tables.def_path_hashes.get(self, index).unwrap())
     }
 
     #[inline]
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 6c758b8e5b6..e967750aebb 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -147,8 +147,7 @@ impl<'a, 'tcx, T: Encodable<EncodeContext<'a, 'tcx>>> Encodable<EncodeContext<'a
     }
 }
 
-impl<'a, 'tcx, I: Idx, T: Encodable<EncodeContext<'a, 'tcx>>> Encodable<EncodeContext<'a, 'tcx>>
-    for Lazy<Table<I, T>>
+impl<'a, 'tcx, I: Idx, T> Encodable<EncodeContext<'a, 'tcx>> for Lazy<Table<I, T>>
 where
     Option<T>: FixedSizeEncoding,
 {
@@ -461,16 +460,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 .chain(self.tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index))
             {
                 let def_key = self.lazy(table.def_key(def_index));
-                let def_path_hash = self.lazy(table.def_path_hash(def_index));
+                let def_path_hash = table.def_path_hash(def_index);
                 self.tables.def_keys.set(def_index, def_key);
                 self.tables.def_path_hashes.set(def_index, def_path_hash);
             }
         } else {
             for (def_index, def_key, def_path_hash) in table.enumerated_keys_and_path_hashes() {
                 let def_key = self.lazy(def_key);
-                let def_path_hash = self.lazy(def_path_hash);
                 self.tables.def_keys.set(def_index, def_key);
-                self.tables.def_path_hashes.set(def_index, def_path_hash);
+                self.tables.def_path_hashes.set(def_index, *def_path_hash);
             }
         }
     }
@@ -988,7 +986,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             let def_id = local_id.to_def_id();
             let def_kind = tcx.opt_def_kind(local_id);
             let Some(def_kind) = def_kind else { continue };
-            record!(self.tables.opt_def_kind[def_id] <- def_kind);
+            self.tables.opt_def_kind.set(def_id.index, def_kind);
             record!(self.tables.def_span[def_id] <- tcx.def_span(def_id));
             record!(self.tables.attributes[def_id] <- tcx.get_attrs(def_id));
             record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
@@ -1048,7 +1046,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         };
 
         record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
-        record!(self.tables.impl_constness[def_id] <- hir::Constness::Const);
+        self.tables.impl_constness.set(def_id.index, hir::Constness::Const);
         record!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
             assert!(f.did.is_local());
             f.did.index
@@ -1078,7 +1076,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         };
 
         record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
-        record!(self.tables.impl_constness[def_id] <- hir::Constness::Const);
+        self.tables.impl_constness.set(def_id.index, hir::Constness::Const);
         self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
@@ -1157,7 +1155,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         };
 
         record!(self.tables.repr_options[def_id] <- adt_def.repr());
-        record!(self.tables.impl_constness[def_id] <- hir::Constness::Const);
+        self.tables.impl_constness.set(def_id.index, hir::Constness::Const);
         record!(self.tables.kind[def_id] <- EntryKind::Struct(self.lazy(data)));
         self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
@@ -1207,8 +1205,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                         record!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body))
                     }
                 };
-                record!(self.tables.asyncness[def_id] <- m_sig.header.asyncness);
-                record!(self.tables.impl_constness[def_id] <- hir::Constness::NotConst);
+                self.tables.asyncness.set(def_id.index, m_sig.header.asyncness);
+                self.tables.impl_constness.set(def_id.index, hir::Constness::NotConst);
                 record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData {
                     container,
                     has_self: trait_item.fn_has_self_parameter,
@@ -1265,7 +1263,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
             ty::AssocKind::Fn => {
                 let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() };
-                record!(self.tables.asyncness[def_id] <- sig.header.asyncness);
+                self.tables.asyncness.set(def_id.index, sig.header.asyncness);
                 record!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
                 // Can be inside `impl const Trait`, so using sig.header.constness is not reliable
                 let constness = if self.tcx.is_const_fn_raw(def_id) {
@@ -1273,7 +1271,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 } else {
                     hir::Constness::NotConst
                 };
-                record!(self.tables.impl_constness[def_id] <- constness);
+                self.tables.impl_constness.set(def_id.index, constness);
                 record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData {
                     container,
                     has_self: impl_item.fn_has_self_parameter,
@@ -1286,7 +1284,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         self.encode_ident_span(def_id, impl_item.ident(self.tcx));
         self.encode_item_type(def_id);
         if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
-            record!(self.tables.trait_item_def_id[def_id] <- trait_item_def_id);
+            self.tables.trait_item_def_id.set(def_id.index, trait_item_def_id.into());
         }
         if impl_item.kind == ty::AssocKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
@@ -1394,9 +1392,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 EntryKind::Const
             }
             hir::ItemKind::Fn(ref sig, .., body) => {
-                record!(self.tables.asyncness[def_id] <- sig.header.asyncness);
+                self.tables.asyncness.set(def_id.index, sig.header.asyncness);
                 record!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
-                record!(self.tables.impl_constness[def_id] <- sig.header.constness);
+                self.tables.impl_constness.set(def_id.index, sig.header.constness);
                 EntryKind::Fn
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
@@ -1420,7 +1418,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             hir::ItemKind::Struct(ref struct_def, _) => {
                 let adt_def = self.tcx.adt_def(def_id);
                 record!(self.tables.repr_options[def_id] <- adt_def.repr());
-                record!(self.tables.impl_constness[def_id] <- hir::Constness::Const);
+                self.tables.impl_constness.set(def_id.index, hir::Constness::Const);
 
                 // Encode def_ids for each field and method
                 // for methods, write all the stuff get_trait_method
@@ -1450,15 +1448,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 }))
             }
             hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
-                record!(self.tables.impl_defaultness[def_id] <- defaultness);
-                record!(self.tables.impl_constness[def_id] <- constness);
+                self.tables.impl_defaultness.set(def_id.index, defaultness);
+                self.tables.impl_constness.set(def_id.index, constness);
 
                 let trait_ref = self.tcx.impl_trait_ref(def_id);
                 if let Some(trait_ref) = trait_ref {
                     let trait_def = self.tcx.trait_def(trait_ref.def_id);
                     if let Some(mut an) = trait_def.ancestors(self.tcx, def_id).ok() {
                         if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) {
-                            record!(self.tables.impl_parent[def_id] <- parent);
+                            self.tables.impl_parent.set(def_id.index, parent.into());
                         }
                     }
 
@@ -1472,7 +1470,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 }
 
                 let polarity = self.tcx.impl_polarity(def_id);
-                record!(self.tables.impl_polarity[def_id] <- polarity);
+                self.tables.impl_polarity.set(def_id.index, polarity);
 
                 EntryKind::Impl
             }
@@ -1644,7 +1642,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 self.tables.proc_macro_quoted_spans.set(i, span);
             }
 
-            record!(self.tables.opt_def_kind[LOCAL_CRATE.as_def_id()] <- DefKind::Mod);
+            self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod);
             record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
             record!(self.tables.attributes[LOCAL_CRATE.as_def_id()] <- tcx.get_attrs(LOCAL_CRATE.as_def_id()));
             record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id()));
@@ -1685,7 +1683,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 def_key.disambiguated_data.data = DefPathData::MacroNs(name);
 
                 let def_id = id.to_def_id();
-                record!(self.tables.opt_def_kind[def_id] <- DefKind::Macro(macro_kind));
+                self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind));
                 record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind));
                 record!(self.tables.attributes[def_id] <- attrs);
                 record!(self.tables.def_keys[def_id] <- def_key);
@@ -1886,14 +1884,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         match nitem.kind {
             hir::ForeignItemKind::Fn(_, ref names, _) => {
-                record!(self.tables.asyncness[def_id] <- hir::IsAsync::NotAsync);
+                self.tables.asyncness.set(def_id.index, hir::IsAsync::NotAsync);
                 record!(self.tables.fn_arg_names[def_id] <- *names);
                 let constness = if self.tcx.is_const_fn_raw(def_id) {
                     hir::Constness::Const
                 } else {
                     hir::Constness::NotConst
                 };
-                record!(self.tables.impl_constness[def_id] <- constness);
+                self.tables.impl_constness.set(def_id.index, constness);
                 record!(self.tables.kind[def_id] <- EntryKind::ForeignFn);
             }
             hir::ForeignItemKind::Static(..) => {
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 15e8693d712..43ccfc64e05 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -1,3 +1,4 @@
+use crate::creader::CrateMetadataRef;
 use decoder::Metadata;
 use def_path_hash_map::DefPathHashMapRef;
 use table::{Table, TableBuilder};
@@ -8,7 +9,7 @@ use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::MetadataRef;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind};
-use rustc_hir::def_id::{DefId, DefIndex, DefPathHash, StableCrateId};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId};
 use rustc_hir::definitions::DefKey;
 use rustc_hir::lang_items;
 use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
@@ -237,6 +238,29 @@ crate struct CrateRoot<'tcx> {
     symbol_mangling_version: SymbolManglingVersion,
 }
 
+/// On-disk representation of `DefId`.
+/// This creates a type-safe way to enforce that we remap the CrateNum between the on-disk
+/// representation and the compilation session.
+#[derive(Copy, Clone)]
+crate struct RawDefId {
+    krate: u32,
+    index: u32,
+}
+
+impl Into<RawDefId> for DefId {
+    fn into(self) -> RawDefId {
+        RawDefId { krate: self.krate.as_u32(), index: self.index.as_u32() }
+    }
+}
+
+impl RawDefId {
+    fn decode(self, cdata: CrateMetadataRef<'_>) -> DefId {
+        let krate = CrateNum::from_u32(self.krate);
+        let krate = cdata.map_encoded_cnum_to_current(krate);
+        DefId { krate, index: DefIndex::from_u32(self.index) }
+    }
+}
+
 #[derive(Encodable, Decodable)]
 crate struct CrateDep {
     pub name: Symbol,
@@ -286,7 +310,7 @@ define_tables! {
     attributes: Table<DefIndex, Lazy<[ast::Attribute]>>,
     children: Table<DefIndex, Lazy<[DefIndex]>>,
 
-    opt_def_kind: Table<DefIndex, Lazy<DefKind>>,
+    opt_def_kind: Table<DefIndex, DefKind>,
     visibility: Table<DefIndex, Lazy<ty::Visibility>>,
     def_span: Table<DefIndex, Lazy<Span>>,
     def_ident_span: Table<DefIndex, Lazy<Span>>,
@@ -309,20 +333,20 @@ define_tables! {
     mir_for_ctfe: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
     promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
     thir_abstract_const: Table<DefIndex, Lazy!(&'tcx [thir::abstract_const::Node<'tcx>])>,
-    impl_parent: Table<DefIndex, Lazy!(DefId)>,
-    impl_polarity: Table<DefIndex, Lazy!(ty::ImplPolarity)>,
-    impl_constness: Table<DefIndex, Lazy!(hir::Constness)>,
-    impl_defaultness: Table<DefIndex, Lazy!(hir::Defaultness)>,
+    impl_parent: Table<DefIndex, RawDefId>,
+    impl_polarity: Table<DefIndex, ty::ImplPolarity>,
+    impl_constness: Table<DefIndex, hir::Constness>,
+    impl_defaultness: Table<DefIndex, hir::Defaultness>,
     // FIXME(eddyb) perhaps compute this on the fly if cheap enough?
     coerce_unsized_info: Table<DefIndex, Lazy!(ty::adjustment::CoerceUnsizedInfo)>,
     mir_const_qualif: Table<DefIndex, Lazy!(mir::ConstQualifs)>,
     rendered_const: Table<DefIndex, Lazy!(String)>,
-    asyncness: Table<DefIndex, Lazy!(hir::IsAsync)>,
+    asyncness: Table<DefIndex, hir::IsAsync>,
     fn_arg_names: Table<DefIndex, Lazy!([Ident])>,
     generator_kind: Table<DefIndex, Lazy!(hir::GeneratorKind)>,
     trait_def: Table<DefIndex, Lazy!(ty::TraitDef)>,
 
-    trait_item_def_id: Table<DefIndex, Lazy<DefId>>,
+    trait_item_def_id: Table<DefIndex, RawDefId>,
     inherent_impls: Table<DefIndex, Lazy<[DefIndex]>>,
     expn_that_defined: Table<DefIndex, Lazy<ExpnId>>,
     unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
@@ -332,7 +356,7 @@ define_tables! {
     // `DefPathTable` up front, since we may only ever use a few
     // definitions from any given crate.
     def_keys: Table<DefIndex, Lazy<DefKey>>,
-    def_path_hashes: Table<DefIndex, Lazy<DefPathHash>>,
+    def_path_hashes: Table<DefIndex, DefPathHash>,
     proc_macro_quoted_spans: Table<usize, Lazy<Span>>,
 }
 
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index 265ca5a6d8d..7a23cba536a 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -1,8 +1,11 @@
 use crate::rmeta::*;
 
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_hir::def::{CtorKind, CtorOf};
 use rustc_index::vec::Idx;
 use rustc_serialize::opaque::Encoder;
 use rustc_serialize::Encoder as _;
+use rustc_span::hygiene::MacroKind;
 use std::convert::TryInto;
 use std::marker::PhantomData;
 use std::num::NonZeroUsize;
@@ -13,66 +16,173 @@ use tracing::debug;
 /// Unchecked invariant: `Self::default()` should encode as `[0; BYTE_LEN]`,
 /// but this has no impact on safety.
 pub(super) trait FixedSizeEncoding: Default {
-    const BYTE_LEN: usize;
-
-    // FIXME(eddyb) convert to and from `[u8; Self::BYTE_LEN]` instead,
-    // once that starts being allowed by the compiler (i.e. lazy normalization).
-    fn from_bytes(b: &[u8]) -> Self;
-    fn write_to_bytes(self, b: &mut [u8]);
-
-    // FIXME(eddyb) make these generic functions, or at least defaults here.
-    // (same problem as above, needs `[u8; Self::BYTE_LEN]`)
-    // For now, a macro (`fixed_size_encoding_byte_len_and_defaults`) is used.
-
-    /// Read a `Self` value (encoded as `Self::BYTE_LEN` bytes),
-    /// from `&b[i * Self::BYTE_LEN..]`, returning `None` if `i`
-    /// is not in bounds, or `Some(Self::from_bytes(...))` otherwise.
-    fn maybe_read_from_bytes_at(b: &[u8], i: usize) -> Option<Self>;
-    /// Write a `Self` value (encoded as `Self::BYTE_LEN` bytes),
-    /// at `&mut b[i * Self::BYTE_LEN..]`, using `Self::write_to_bytes`.
-    fn write_to_bytes_at(self, b: &mut [u8], i: usize);
-}
-
-// HACK(eddyb) this shouldn't be needed (see comments on the methods above).
-macro_rules! fixed_size_encoding_byte_len_and_defaults {
-    ($byte_len:expr) => {
-        const BYTE_LEN: usize = $byte_len;
-        fn maybe_read_from_bytes_at(b: &[u8], i: usize) -> Option<Self> {
-            const BYTE_LEN: usize = $byte_len;
-            // HACK(eddyb) ideally this would be done with fully safe code,
-            // but slicing `[u8]` with `i * N..` is optimized worse, due to the
-            // possibility of `i * N` overflowing, than indexing `[[u8; N]]`.
-            let b = unsafe {
-                std::slice::from_raw_parts(b.as_ptr() as *const [u8; BYTE_LEN], b.len() / BYTE_LEN)
-            };
-            b.get(i).map(|b| FixedSizeEncoding::from_bytes(b))
-        }
-        fn write_to_bytes_at(self, b: &mut [u8], i: usize) {
-            const BYTE_LEN: usize = $byte_len;
-            // HACK(eddyb) ideally this would be done with fully safe code,
-            // see similar comment in `read_from_bytes_at` for why it can't yet.
-            let b = unsafe {
-                std::slice::from_raw_parts_mut(
-                    b.as_mut_ptr() as *mut [u8; BYTE_LEN],
-                    b.len() / BYTE_LEN,
-                )
-            };
-            self.write_to_bytes(&mut b[i]);
-        }
-    };
+    /// This should be `[u8; BYTE_LEN]`;
+    type ByteArray;
+
+    fn from_bytes(b: &Self::ByteArray) -> Self;
+    fn write_to_bytes(self, b: &mut Self::ByteArray);
 }
 
 impl FixedSizeEncoding for u32 {
-    fixed_size_encoding_byte_len_and_defaults!(4);
+    type ByteArray = [u8; 4];
+
+    #[inline]
+    fn from_bytes(b: &[u8; 4]) -> Self {
+        Self::from_le_bytes(*b)
+    }
+
+    #[inline]
+    fn write_to_bytes(self, b: &mut [u8; 4]) {
+        *b = self.to_le_bytes();
+    }
+}
+
+macro_rules! fixed_size_enum {
+    ($ty:ty { $(($($pat:tt)*))* }) => {
+        impl FixedSizeEncoding for Option<$ty> {
+            type ByteArray = [u8;1];
+
+            #[inline]
+            fn from_bytes(b: &[u8;1]) -> Self {
+                use $ty::*;
+                if b[0] == 0 {
+                    return None;
+                }
+                match b[0] - 1 {
+                    $(${index()} => Some($($pat)*),)*
+                    _ => panic!("Unexpected ImplPolarity code: {:?}", b[0]),
+                }
+            }
+
+            #[inline]
+            fn write_to_bytes(self, b: &mut [u8;1]) {
+                use $ty::*;
+                b[0] = match self {
+                    None => 0,
+                    $(Some($($pat)*) => 1 + ${index()},)*
+                }
+            }
+        }
+    }
+}
+
+fixed_size_enum! {
+    DefKind {
+        ( Mod                                      )
+        ( Struct                                   )
+        ( Union                                    )
+        ( Enum                                     )
+        ( Variant                                  )
+        ( Trait                                    )
+        ( TyAlias                                  )
+        ( ForeignTy                                )
+        ( TraitAlias                               )
+        ( AssocTy                                  )
+        ( TyParam                                  )
+        ( Fn                                       )
+        ( Const                                    )
+        ( ConstParam                               )
+        ( AssocFn                                  )
+        ( AssocConst                               )
+        ( ExternCrate                              )
+        ( Use                                      )
+        ( ForeignMod                               )
+        ( AnonConst                                )
+        ( InlineConst                              )
+        ( OpaqueTy                                 )
+        ( Field                                    )
+        ( LifetimeParam                            )
+        ( GlobalAsm                                )
+        ( Impl                                     )
+        ( Closure                                  )
+        ( Generator                                )
+        ( Static(ast::Mutability::Not)             )
+        ( Static(ast::Mutability::Mut)             )
+        ( Ctor(CtorOf::Struct, CtorKind::Fn)       )
+        ( Ctor(CtorOf::Struct, CtorKind::Const)    )
+        ( Ctor(CtorOf::Struct, CtorKind::Fictive)  )
+        ( Ctor(CtorOf::Variant, CtorKind::Fn)      )
+        ( Ctor(CtorOf::Variant, CtorKind::Const)   )
+        ( Ctor(CtorOf::Variant, CtorKind::Fictive) )
+        ( Macro(MacroKind::Bang)                   )
+        ( Macro(MacroKind::Attr)                   )
+        ( Macro(MacroKind::Derive)                 )
+    }
+}
+
+fixed_size_enum! {
+    ty::ImplPolarity {
+        ( Positive    )
+        ( Negative    )
+        ( Reservation )
+    }
+}
+
+fixed_size_enum! {
+    hir::Constness {
+        ( NotConst )
+        ( Const    )
+    }
+}
 
-    fn from_bytes(b: &[u8]) -> Self {
-        let mut bytes = [0; Self::BYTE_LEN];
-        bytes.copy_from_slice(&b[..Self::BYTE_LEN]);
-        Self::from_le_bytes(bytes)
+fixed_size_enum! {
+    hir::Defaultness {
+        ( Final                        )
+        ( Default { has_value: false } )
+        ( Default { has_value: true }  )
     }
+}
 
-    fn write_to_bytes(self, b: &mut [u8]) {
-        b[..Self::BYTE_LEN].copy_from_slice(&self.to_le_bytes());
+fixed_size_enum! {
+    hir::IsAsync {
+        ( NotAsync )
+        ( Async    )
+    }
+}
+
+// We directly encode `DefPathHash` because a `Lazy` would encur a 25% cost.
+impl FixedSizeEncoding for Option<DefPathHash> {
+    type ByteArray = [u8; 16];
+
+    #[inline]
+    fn from_bytes(b: &[u8; 16]) -> Self {
+        Some(DefPathHash(Fingerprint::from_le_bytes(*b)))
+    }
+
+    #[inline]
+    fn write_to_bytes(self, b: &mut [u8; 16]) {
+        let Some(DefPathHash(fingerprint)) = self else {
+            panic!("Trying to encode absent DefPathHash.")
+        };
+        *b = fingerprint.to_le_bytes();
+    }
+}
+
+// We directly encode RawDefId because using a `Lazy` would incur a 50% overhead in the worst case.
+impl FixedSizeEncoding for Option<RawDefId> {
+    type ByteArray = [u8; 8];
+
+    #[inline]
+    fn from_bytes(b: &[u8; 8]) -> Self {
+        let krate = u32::from_le_bytes(b[0..4].try_into().unwrap());
+        let index = u32::from_le_bytes(b[4..8].try_into().unwrap());
+        if krate == 0 {
+            return None;
+        }
+        Some(RawDefId { krate: krate - 1, index })
+    }
+
+    #[inline]
+    fn write_to_bytes(self, b: &mut [u8; 8]) {
+        match self {
+            None => *b = [0; 8],
+            Some(RawDefId { krate, index }) => {
+                // CrateNum is less than `CrateNum::MAX_AS_U32`.
+                debug_assert!(krate < u32::MAX);
+                b[0..4].copy_from_slice(&(1 + krate).to_le_bytes());
+                b[4..8].copy_from_slice(&index.to_le_bytes());
+            }
+        }
     }
 }
 
@@ -80,44 +190,51 @@ impl FixedSizeEncoding for u32 {
 // generic `Lazy<T>` impl, but in the general case we might not need / want to
 // fit every `usize` in `u32`.
 impl<T> FixedSizeEncoding for Option<Lazy<T>> {
-    fixed_size_encoding_byte_len_and_defaults!(u32::BYTE_LEN);
+    type ByteArray = [u8; 4];
 
-    fn from_bytes(b: &[u8]) -> Self {
-        Some(Lazy::from_position(NonZeroUsize::new(u32::from_bytes(b) as usize)?))
+    #[inline]
+    fn from_bytes(b: &[u8; 4]) -> Self {
+        let position = NonZeroUsize::new(u32::from_bytes(b) as usize)?;
+        Some(Lazy::from_position(position))
     }
 
-    fn write_to_bytes(self, b: &mut [u8]) {
+    #[inline]
+    fn write_to_bytes(self, b: &mut [u8; 4]) {
         let position = self.map_or(0, |lazy| lazy.position.get());
         let position: u32 = position.try_into().unwrap();
-
         position.write_to_bytes(b)
     }
 }
 
 impl<T> FixedSizeEncoding for Option<Lazy<[T]>> {
-    fixed_size_encoding_byte_len_and_defaults!(u32::BYTE_LEN * 2);
+    type ByteArray = [u8; 8];
 
-    fn from_bytes(b: &[u8]) -> Self {
-        Some(Lazy::from_position_and_meta(
-            <Option<Lazy<T>>>::from_bytes(b)?.position,
-            u32::from_bytes(&b[u32::BYTE_LEN..]) as usize,
-        ))
+    #[inline]
+    fn from_bytes(b: &[u8; 8]) -> Self {
+        let ([ref position_bytes, ref meta_bytes],[])= b.as_chunks::<4>() else { panic!() };
+        let position = NonZeroUsize::new(u32::from_bytes(position_bytes) as usize)?;
+        let len = u32::from_bytes(meta_bytes) as usize;
+        Some(Lazy::from_position_and_meta(position, len))
     }
 
-    fn write_to_bytes(self, b: &mut [u8]) {
-        self.map(|lazy| Lazy::<T>::from_position(lazy.position)).write_to_bytes(b);
+    #[inline]
+    fn write_to_bytes(self, b: &mut [u8; 8]) {
+        let ([ref mut position_bytes, ref mut meta_bytes],[])= b.as_chunks_mut::<4>() else { panic!() };
+
+        let position = self.map_or(0, |lazy| lazy.position.get());
+        let position: u32 = position.try_into().unwrap();
+        position.write_to_bytes(position_bytes);
 
         let len = self.map_or(0, |lazy| lazy.meta);
         let len: u32 = len.try_into().unwrap();
-
-        len.write_to_bytes(&mut b[u32::BYTE_LEN..]);
+        len.write_to_bytes(meta_bytes);
     }
 }
 
 /// Random-access table (i.e. offering constant-time `get`/`set`), similar to
 /// `Vec<Option<T>>`, but without requiring encoding or decoding all the values
 /// eagerly and in-order.
-/// A total of `(max_idx + 1) * <Option<T> as FixedSizeEncoding>::BYTE_LEN` bytes
+/// A total of `(max_idx + 1)` times `Option<T> as FixedSizeEncoding>::ByteArray`
 /// are used for a table, where `max_idx` is the largest index passed to
 /// `TableBuilder::set`.
 pub(super) struct Table<I: Idx, T>
@@ -135,12 +252,8 @@ pub(super) struct TableBuilder<I: Idx, T>
 where
     Option<T>: FixedSizeEncoding,
 {
-    // FIXME(eddyb) use `IndexVec<I, [u8; <Option<T>>::BYTE_LEN]>` instead of
-    // `Vec<u8>`, once that starts working (i.e. lazy normalization).
-    // Then again, that has the downside of not allowing `TableBuilder::encode` to
-    // obtain a `&[u8]` entirely in safe code, for writing the bytes out.
-    bytes: Vec<u8>,
-    _marker: PhantomData<(fn(&I), T)>,
+    blocks: IndexVec<I, <Option<T> as FixedSizeEncoding>::ByteArray>,
+    _marker: PhantomData<T>,
 }
 
 impl<I: Idx, T> Default for TableBuilder<I, T>
@@ -148,7 +261,7 @@ where
     Option<T>: FixedSizeEncoding,
 {
     fn default() -> Self {
-        TableBuilder { bytes: vec![], _marker: PhantomData }
+        TableBuilder { blocks: Default::default(), _marker: PhantomData }
     }
 }
 
@@ -156,25 +269,29 @@ impl<I: Idx, T> TableBuilder<I, T>
 where
     Option<T>: FixedSizeEncoding,
 {
-    pub(crate) fn set(&mut self, i: I, value: T) {
+    pub(crate) fn set<const N: usize>(&mut self, i: I, value: T)
+    where
+        Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
+    {
         // FIXME(eddyb) investigate more compact encodings for sparse tables.
         // On the PR @michaelwoerister mentioned:
         // > Space requirements could perhaps be optimized by using the HAMT `popcnt`
         // > trick (i.e. divide things into buckets of 32 or 64 items and then
         // > store bit-masks of which item in each bucket is actually serialized).
-        let i = i.index();
-        let needed = (i + 1) * <Option<T>>::BYTE_LEN;
-        if self.bytes.len() < needed {
-            self.bytes.resize(needed, 0);
-        }
-
-        Some(value).write_to_bytes_at(&mut self.bytes, i);
+        self.blocks.ensure_contains_elem(i, || [0; N]);
+        Some(value).write_to_bytes(&mut self.blocks[i]);
     }
 
-    pub(crate) fn encode(&self, buf: &mut Encoder) -> Lazy<Table<I, T>> {
+    pub(crate) fn encode<const N: usize>(&self, buf: &mut Encoder) -> Lazy<Table<I, T>>
+    where
+        Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
+    {
         let pos = buf.position();
-        buf.emit_raw_bytes(&self.bytes).unwrap();
-        Lazy::from_position_and_meta(NonZeroUsize::new(pos as usize).unwrap(), self.bytes.len())
+        for block in &self.blocks {
+            buf.emit_raw_bytes(block).unwrap();
+        }
+        let num_bytes = self.blocks.len() * N;
+        Lazy::from_position_and_meta(NonZeroUsize::new(pos as usize).unwrap(), num_bytes)
     }
 }
 
@@ -182,6 +299,7 @@ impl<I: Idx, T> LazyMeta for Table<I, T>
 where
     Option<T>: FixedSizeEncoding,
 {
+    /// Number of bytes in the data stream.
     type Meta = usize;
 }
 
@@ -191,16 +309,28 @@ where
 {
     /// Given the metadata, extract out the value at a particular index (if any).
     #[inline(never)]
-    pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>>(&self, metadata: M, i: I) -> Option<T> {
+    pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>, const N: usize>(
+        &self,
+        metadata: M,
+        i: I,
+    ) -> Option<T>
+    where
+        Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
+    {
         debug!("Table::lookup: index={:?} len={:?}", i, self.meta);
 
         let start = self.position.get();
         let bytes = &metadata.blob()[start..start + self.meta];
-        <Option<T>>::maybe_read_from_bytes_at(bytes, i.index())?
+        let (bytes, []) = bytes.as_chunks::<N>() else { panic!() };
+        let bytes = bytes.get(i.index())?;
+        FixedSizeEncoding::from_bytes(bytes)
     }
 
     /// Size of the table in entries, including possible gaps.
-    pub(super) fn size(&self) -> usize {
-        self.meta / <Option<T>>::BYTE_LEN
+    pub(super) fn size<const N: usize>(&self) -> usize
+    where
+        Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
+    {
+        self.meta / N
     }
 }
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index fa2dad5ce25..fd2b5f5335f 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -59,6 +59,7 @@
 #![feature(unwrap_infallible)]
 #![feature(decl_macro)]
 #![feature(drain_filter)]
+#![feature(intra_doc_pointers)]
 #![recursion_limit = "512"]
 #![allow(rustc::potential_query_instability)]
 
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 0a4f84558fe..9f7832c8a64 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -127,12 +127,24 @@ pub trait MirPass<'tcx> {
 /// The various "big phases" that MIR goes through.
 ///
 /// These phases all describe dialects of MIR. Since all MIR uses the same datastructures, the
-/// dialects forbid certain variants or values in certain phases.
+/// dialects forbid certain variants or values in certain phases. The sections below summarize the
+/// changes, but do not document them thoroughly. The full documentation is found in the appropriate
+/// documentation for the thing the change is affecting.
 ///
 /// Warning: ordering of variants is significant.
 #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
 #[derive(HashStable)]
 pub enum MirPhase {
+    /// The dialect of MIR used during all phases before `DropsLowered` is the same. This is also
+    /// the MIR that analysis such as borrowck uses.
+    ///
+    /// One important thing to remember about the behavior of this section of MIR is that drop terminators
+    /// (including drop and replace) are *conditional*. The elaborate drops pass will then replace each
+    /// instance of a drop terminator with a nop, an unconditional drop, or a drop conditioned on a drop
+    /// flag. Of course, this means that it is important that the drop elaboration can accurately recognize
+    /// when things are initialized and when things are de-initialized. That means any code running on this
+    /// version of MIR must be sure to produce output that drop elaboration can reason about. See the
+    /// section on the drop terminatorss for more details.
     Built = 0,
     // FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query).
     // We used to have this for pre-miri MIR based const eval.
@@ -162,6 +174,16 @@ pub enum MirPhase {
     /// And the following variant is allowed:
     /// * [`StatementKind::SetDiscriminant`]
     Deaggregated = 4,
+    /// Before this phase, generators are in the "source code" form, featuring `yield` statements
+    /// and such. With this phase change, they are transformed into a proper state machine. Running
+    /// optimizations before this change can be potentially dangerous because the source code is to
+    /// some extent a "lie." In particular, `yield` terminators effectively make the value of all
+    /// locals visible to the caller. This means that dead store elimination before them, or code
+    /// motion across them, is not correct in general. This is also exasperated by type checking
+    /// having pre-computed a list of the types that it thinks are ok to be live across a yield
+    /// point - this is necessary to decide eg whether autotraits are implemented. Introducing new
+    /// types across a yield point will lead to ICEs becaues of this.
+    ///
     /// Beginning with this phase, the following variants are disallowed:
     /// * [`TerminatorKind::Yield`](terminator::TerminatorKind::Yield)
     /// * [`TerminatorKind::GeneratorDrop](terminator::TerminatorKind::GeneratorDrop)
@@ -1573,34 +1595,88 @@ impl Statement<'_> {
 /// causing an ICE if they are violated.
 #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
 pub enum StatementKind<'tcx> {
-    /// Write the RHS Rvalue to the LHS Place.
+    /// Assign statements roughly correspond to an assignment in Rust proper (`x = ...`) except
+    /// without the possibility of dropping the previous value (that must be done separately, if at
+    /// all). The *exact* way this works is undecided. It probably does something like evaluating
+    /// the LHS to a place and the RHS to a value, and then storing the value to the place. Various
+    /// parts of this may do type specific things that are more complicated than simply copying
+    /// bytes.
+    ///
+    /// **Needs clarification**: The implication of the above idea would be that assignment implies
+    /// that the resulting value is initialized. I believe we could commit to this separately from
+    /// committing to whatever part of the memory model we would need to decide on to make the above
+    /// paragragh precise. Do we want to?
+    ///
+    /// Assignments in which the types of the place and rvalue differ are not well-formed.
+    ///
+    /// **Needs clarification**: Do we ever want to worry about non-free (in the body) lifetimes for
+    /// the typing requirement in post drop-elaboration MIR? I think probably not - I'm not sure we
+    /// could meaningfully require this anyway. How about free lifetimes? Is ignoring this
+    /// interesting for optimizations? Do we want to allow such optimizations?
     ///
-    /// The LHS place may not overlap with any memory accessed on the RHS.
+    /// **Needs clarification**: We currently require that the LHS place not overlap with any place
+    /// read as part of computation of the RHS for some rvalues (generally those not producing
+    /// primitives). This requirement is under discussion in [#68364]. As a part of this discussion,
+    /// it is also unclear in what order the components are evaluated.
+    ///
+    /// [#68364]: https://github.com/rust-lang/rust/issues/68364
+    ///
+    /// See [`Rvalue`] documentation for details on each of those.
     Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>),
 
-    /// This represents all the reading that a pattern match may do
-    /// (e.g., inspecting constants and discriminant values), and the
-    /// kind of pattern it comes from. This is in order to adapt potential
-    /// error messages to these specific patterns.
+    /// This represents all the reading that a pattern match may do (e.g., inspecting constants and
+    /// discriminant values), and the kind of pattern it comes from. This is in order to adapt
+    /// potential error messages to these specific patterns.
     ///
     /// Note that this also is emitted for regular `let` bindings to ensure that locals that are
     /// never accessed still get some sanity checks for, e.g., `let x: ! = ..;`
+    ///
+    /// When executed at runtime this is a nop.
+    ///
+    /// Disallowed after drop elaboration.
     FakeRead(Box<(FakeReadCause, Place<'tcx>)>),
 
     /// Write the discriminant for a variant to the enum Place.
+    ///
+    /// This is permitted for both generators and ADTs. This does not necessarily write to the
+    /// entire place; instead, it writes to the minimum set of bytes as required by the layout for
+    /// the type.
     SetDiscriminant { place: Box<Place<'tcx>>, variant_index: VariantIdx },
 
-    /// Start a live range for the storage of the local.
+    /// Deinitializes the place.
+    ///
+    /// This writes `uninit` bytes to the entire place.
+    Deinit(Box<Place<'tcx>>),
+
+    /// `StorageLive` and `StorageDead` statements mark the live range of a local.
+    ///
+    /// Using a local before a `StorageLive` or after a `StorageDead` is not well-formed. These
+    /// statements are not required. If the entire MIR body contains no `StorageLive`/`StorageDead`
+    /// statements for a particular local, the local is always considered live.
+    ///
+    /// More precisely, the MIR validator currently does a `MaybeStorageLiveLocals` analysis to
+    /// check validity of each use of a local. I believe this is equivalent to requiring for every
+    /// use of a local, there exist at least one path from the root to that use that contains a
+    /// `StorageLive` more recently than a `StorageDead`.
+    ///
+    /// **Needs clarification**: Is it permitted to have two `StorageLive`s without an intervening
+    /// `StorageDead`? Two `StorageDead`s without an intervening `StorageLive`? LLVM says poison,
+    /// yes. If the answer to any of these is "no," is breaking that rule UB or is it an error to
+    /// have a path in the CFG that might do this?
     StorageLive(Local),
 
-    /// End the current live range for the storage of the local.
+    /// See `StorageLive` above.
     StorageDead(Local),
 
-    /// Retag references in the given place, ensuring they got fresh tags. This is
-    /// part of the Stacked Borrows model. These statements are currently only interpreted
-    /// by miri and only generated when "-Z mir-emit-retag" is passed.
-    /// See <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/>
-    /// for more details.
+    /// Retag references in the given place, ensuring they got fresh tags.
+    ///
+    /// This is part of the Stacked Borrows model. These statements are currently only interpreted
+    /// by miri and only generated when `-Z mir-emit-retag` is passed. See
+    /// <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/> for
+    /// more details.
+    ///
+    /// For code that is not specific to stacked borrows, you should consider retags to read
+    /// and modify the place in an opaque way.
     Retag(RetagKind, Box<Place<'tcx>>),
 
     /// Encodes a user's type ascription. These need to be preserved
@@ -1615,6 +1691,10 @@ pub enum StatementKind<'tcx> {
     /// - `Contravariant` -- requires that `T_y :> T`
     /// - `Invariant` -- requires that `T_y == T`
     /// - `Bivariant` -- no effect
+    ///
+    /// When executed at runtime this is a nop.
+    ///
+    /// Disallowed after drop elaboration.
     AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance),
 
     /// Marks the start of a "coverage region", injected with '-Cinstrument-coverage'. A
@@ -1624,9 +1704,19 @@ pub enum StatementKind<'tcx> {
     /// executed.
     Coverage(Box<Coverage>),
 
-    /// Denotes a call to the intrinsic function copy_overlapping, where `src_dst` denotes the
-    /// memory being read from and written to(one field to save memory), and size
-    /// indicates how many bytes are being copied over.
+    /// Denotes a call to the intrinsic function `copy_nonoverlapping`.
+    ///
+    /// First, all three operands are evaluated. `src` and `dest` must each be a reference, pointer,
+    /// or `Box` pointing to the same type `T`. `count` must evaluate to a `usize`. Then, `src` and
+    /// `dest` are dereferenced, and `count * size_of::<T>()` bytes beginning with the first byte of
+    /// the `src` place are copied to the continguous range of bytes beginning with the first byte
+    /// of `dest`.
+    ///
+    /// **Needs clarification**: In what order are operands computed and dereferenced? It should
+    /// probably match the order for assignment, but that is also undecided.
+    ///
+    /// **Needs clarification**: Is this typed or not, ie is there a typed load and store involved?
+    /// I vaguely remember Ralf saying somewhere that he thought it should not be.
     CopyNonOverlapping(Box<CopyNonOverlapping<'tcx>>),
 
     /// No-op. Useful for deleting instructions without affecting statement indices.
@@ -1739,6 +1829,7 @@ impl Debug for Statement<'_> {
             SetDiscriminant { ref place, variant_index } => {
                 write!(fmt, "discriminant({:?}) = {:?}", place, variant_index)
             }
+            Deinit(ref place) => write!(fmt, "Deinit({:?})", place),
             AscribeUserType(box (ref place, ref c_ty), ref variance) => {
                 write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
             }
@@ -1775,8 +1866,82 @@ pub struct CopyNonOverlapping<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // Places
 
-/// A path to a value; something that can be evaluated without
-/// changing or disturbing program state.
+/// Places roughly correspond to a "location in memory." Places in MIR are the same mathematical
+/// object as places in Rust. This of course means that what exactly they are is undecided and part
+/// of the Rust memory model. However, they will likely contain at least the following pieces of
+/// information in some form:
+///
+///  1. The address in memory that the place refers to.
+///  2. The provenance with which the place is being accessed.
+///  3. The type of the place and an optional variant index. See [`PlaceTy`][tcx::PlaceTy].
+///  4. Optionally, some metadata. This exists if and only if the type of the place is not `Sized`.
+///
+/// We'll give a description below of how all pieces of the place except for the provenance are
+/// calculated. We cannot give a description of the provenance, because that is part of the
+/// undecided aliasing model - we only include it here at all to acknowledge its existence.
+///
+/// Each local naturally corresponds to the place `Place { local, projection: [] }`. This place has
+/// the address of the local's allocation and the type of the local.
+///
+/// **Needs clarification:** Unsized locals seem to present a bit of an issue. Their allocation
+/// can't actually be created on `StorageLive`, because it's unclear how big to make the allocation.
+/// Furthermore, MIR produces assignments to unsized locals, although that is not permitted under
+/// `#![feature(unsized_locals)]` in Rust. Besides just putting "unsized locals are special and
+/// different" in a bunch of places, I (JakobDegen) don't know how to incorporate this behavior into
+/// the current MIR semantics in a clean way - possibly this needs some design work first.
+///
+/// For places that are not locals, ie they have a non-empty list of projections, we define the
+/// values as a function of the parent place, that is the place with its last [`ProjectionElem`]
+/// stripped. The way this is computed of course depends on the kind of that last projection
+/// element:
+///
+///  - [`Downcast`](ProjectionElem::Downcast): This projection sets the place's variant index to the
+///    given one, and makes no other changes. A `Downcast` projection on a place with its variant
+///    index already set is not well-formed.
+///  - [`Field`](ProjectionElem::Field): `Field` projections take their parent place and create a
+///    place referring to one of the fields of the type. The resulting address is the parent
+///    address, plus the offset of the field. The type becomes the type of the field. If the parent
+///    was unsized and so had metadata associated with it, then the metadata is retained if the
+///    field is unsized and thrown out if it is sized.
+///
+///    These projections are only legal for tuples, ADTs, closures, and generators. If the ADT or
+///    generator has more than one variant, the parent place's variant index must be set, indicating
+///    which variant is being used. If it has just one variant, the variant index may or may not be
+///    included - the single possible variant is inferred if it is not included.
+///  - [`ConstantIndex`](ProjectionElem::ConstantIndex): Computes an offset in units of `T` into the
+///    place as described in the documentation for the `ProjectionElem`. The resulting address is
+///    the parent's address plus that offset, and the type is `T`. This is only legal if the parent
+///    place has type `[T;  N]` or `[T]` (*not* `&[T]`). Since such a `T` is always sized, any
+///    resulting metadata is thrown out.
+///  - [`Subslice`](ProjectionElem::Subslice): This projection calculates an offset and a new
+///    address in a similar manner as `ConstantIndex`. It is also only legal on `[T; N]` and `[T]`.
+///    However, this yields a `Place` of type `[T]`, and additionally sets the metadata to be the
+///    length of the subslice.
+///  - [`Index`](ProjectionElem::Index): Like `ConstantIndex`, only legal on `[T; N]` or `[T]`.
+///    However, `Index` additionally takes a local from which the value of the index is computed at
+///    runtime. Computing the value of the index involves interpreting the `Local` as a
+///    `Place { local, projection: [] }`, and then computing its value as if done via
+///    [`Operand::Copy`]. The array/slice is then indexed with the resulting value. The local must
+///    have type `usize`.
+///  - [`Deref`](ProjectionElem::Deref): Derefs are the last type of projection, and the most
+///    complicated. They are only legal on parent places that are references, pointers, or `Box`. A
+///    `Deref` projection begins by loading a value from the parent place, as if by
+///    [`Operand::Copy`]. It then dereferences the resulting pointer, creating a place of the
+///    pointee's type. The resulting address is the address that was stored in the pointer. If the
+///    pointee type is unsized, the pointer additionally stored the value of the metadata.
+///
+/// Computing a place may cause UB. One possibility is that the pointer used for a `Deref` may not
+/// be suitably aligned. Another possibility is that the place is not in bounds, meaning it does not
+/// point to an actual allocation.
+///
+/// However, if this is actually UB and when the UB kicks in is undecided. This is being discussed
+/// in [UCG#319]. The options include that every place must obey those rules, that only some places
+/// must obey them, or that places impose no rules of their own.
+///
+/// [UCG#319]: https://github.com/rust-lang/unsafe-code-guidelines/issues/319
+///
+/// Rust currently requires that every place obey those two rules. This is checked by MIRI and taken
+/// advantage of by codegen (via `gep inbounds`). That is possibly subject to change.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, HashStable)]
 pub struct Place<'tcx> {
     pub local: Local,
@@ -2145,24 +2310,39 @@ pub struct SourceScopeLocalData {
 ///////////////////////////////////////////////////////////////////////////
 // Operands
 
-/// These are values that can appear inside an rvalue. They are intentionally
-/// limited to prevent rvalues from being nested in one another.
+/// An operand in MIR represents a "value" in Rust, the definition of which is undecided and part of
+/// the memory model. One proposal for a definition of values can be found [on UCG][value-def].
+///
+/// [value-def]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/value-domain.md
+///
+/// The most common way to create values is via loading a place. Loading a place is an operation
+/// which reads the memory of the place and converts it to a value. This is a fundamentally *typed*
+/// operation. The nature of the value produced depends on the type of the conversion. Furthermore,
+/// there may be other effects: if the type has a validity constraint loading the place might be UB
+/// if the validity constraint is not met.
+///
+/// **Needs clarification:** Ralf proposes that loading a place not have side-effects.
+/// This is what is implemented in miri today. Are these the semantics we want for MIR? Is this
+/// something we can even decide without knowing more about Rust's memory model?
+///
+/// **Needs clarifiation:** Is loading a place that has its variant index set well-formed? Miri
+/// currently implements it, but it seems like this may be something to check against in the
+/// validator.
 #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum Operand<'tcx> {
-    /// Copy: The value must be available for use afterwards.
-    ///
-    /// This implies that the type of the place must be `Copy`; this is true
-    /// by construction during build, but also checked by the MIR type checker.
+    /// Creates a value by loading the given place. The type of the place must be `Copy`
     Copy(Place<'tcx>),
 
-    /// Move: The value (including old borrows of it) will not be used again.
+    /// Creates a value by performing loading the place, just like the `Copy` operand.
+    ///
+    /// This *may* additionally overwrite the place with `uninit` bytes, depending on how we decide
+    /// in [UCG#188]. You should not emit MIR that may attempt a subsequent second load of this
+    /// place without first re-initializing it.
     ///
-    /// Safe for values of all types (modulo future developments towards `?Move`).
-    /// Correct usage patterns are enforced by the borrow checker for safe code.
-    /// `Copy` may be converted to `Move` to enable "last-use" optimizations.
+    /// [UCG#188]: https://github.com/rust-lang/unsafe-code-guidelines/issues/188
     Move(Place<'tcx>),
 
-    /// Synthesizes a constant value.
+    /// Constants are already semantically values, and remain unchanged.
     Constant(Box<Constant<'tcx>>),
 }
 
@@ -2270,57 +2450,134 @@ impl<'tcx> Operand<'tcx> {
 #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
 /// The various kinds of rvalues that can appear in MIR.
 ///
-/// Not all of these are allowed at every [`MirPhase`]. Check the documentation there to see which
-/// ones you do not have to worry about. The MIR validator will generally enforce such restrictions,
-/// causing an ICE if they are violated.
+/// Not all of these are allowed at every [`MirPhase`] - when this is the case, it's stated below.
+///
+/// Computing any rvalue begins by evaluating the places and operands in some order (**Needs
+/// clarification**: Which order?). These are then used to produce a "value" - the same kind of
+/// value that an [`Operand`] produces.
 pub enum Rvalue<'tcx> {
-    /// x (either a move or copy, depending on type of x)
+    /// Yields the operand unchanged
     Use(Operand<'tcx>),
 
-    /// [x; 32]
+    /// Creates an array where each element is the value of the operand.
+    ///
+    /// This is the cause of a bug in the case where the repetition count is zero because the value
+    /// is not dropped, see [#74836].
+    ///
+    /// Corresponds to source code like `[x; 32]`.
+    ///
+    /// [#74836]: https://github.com/rust-lang/rust/issues/74836
     Repeat(Operand<'tcx>, ty::Const<'tcx>),
 
-    /// &x or &mut x
+    /// Creates a reference of the indicated kind to the place.
+    ///
+    /// There is not much to document here, because besides the obvious parts the semantics of this
+    /// are essentially entirely a part of the aliasing model. There are many UCG issues discussing
+    /// exactly what the behavior of this operation should be.
+    ///
+    /// `Shallow` borrows are disallowed after drop lowering.
     Ref(Region<'tcx>, BorrowKind, Place<'tcx>),
 
-    /// Accessing a thread local static. This is inherently a runtime operation, even if llvm
-    /// treats it as an access to a static. This `Rvalue` yields a reference to the thread local
-    /// static.
+    /// Creates a pointer/reference to the given thread local.
+    ///
+    /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a
+    /// `*const T`, and if neither of those apply a `&T`.
+    ///
+    /// **Note:** This is a runtime operation that actually executes code and is in this sense more
+    /// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to
+    /// SIGILL for some reason that I (JakobDegen) never got a chance to look into.
+    ///
+    /// **Needs clarification**: Are there weird additional semantics here related to the runtime
+    /// nature of this operation?
     ThreadLocalRef(DefId),
 
-    /// Create a raw pointer to the given place
-    /// Can be generated by raw address of expressions (`&raw const x`),
-    /// or when casting a reference to a raw pointer.
+    /// Creates a pointer with the indicated mutability to the place.
+    ///
+    /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like
+    /// `&raw v` or `addr_of!(v)`.
+    ///
+    /// Like with references, the semantics of this operation are heavily dependent on the aliasing
+    /// model.
     AddressOf(Mutability, Place<'tcx>),
 
-    /// length of a `[X]` or `[X;n]` value
+    /// Yields the length of the place, as a `usize`.
+    ///
+    /// If the type of the place is an array, this is the array length. For slices (`[T]`, not
+    /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is
+    /// ill-formed for places of other types.
     Len(Place<'tcx>),
 
+    /// Performs essentially all of the casts that can be performed via `as`.
+    ///
+    /// This allows for casts from/to a variety of types.
+    ///
+    /// **FIXME**: Document exactly which `CastKind`s allow which types of casts. Figure out why
+    /// `ArrayToPointer` and `MutToConstPointer` are special.
     Cast(CastKind, Operand<'tcx>, Ty<'tcx>),
 
+    /// * `Offset` has the same semantics as [`offset`](pointer::offset), except that the second
+    ///   parameter may be a `usize` as well.
+    /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
+    ///   raw pointers, or function pointers of matching types and return a `bool`.
+    /// * Left and right shift operations accept signed or unsigned integers not necessarily of the
+    ///   same type and return a value of the same type as their LHS. Like in Rust, the RHS is
+    ///   truncated as needed.
+    /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
+    ///   types and return a value of that type.
+    /// * The remaining operations accept signed integers, unsigned integers, or floats with
+    ///   matching types and return a value of that type.
     BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
+
+    /// Same as `BinaryOp`, but yields `(T, bool)` instead of `T`. In addition to performing the
+    /// same computation as the matching `BinaryOp`, checks if the infinite precison result would be
+    /// unequal to the actual result and sets the `bool` if this is the case.
+    ///
+    /// This only supports addition, subtraction, multiplication, and shift operations on integers.
     CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
 
+    /// Computes a value as described by the operation.
     NullaryOp(NullOp, Ty<'tcx>),
+
+    /// Exactly like `BinaryOp`, but less operands.
+    ///
+    /// Also does two's-complement arithmetic. Negation requires a signed integer or a float;
+    /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds
+    /// return a value with the same type as their operand.
     UnaryOp(UnOp, Operand<'tcx>),
 
-    /// Read the discriminant of an ADT.
+    /// Computes the discriminant of the place, returning it as an integer of type
+    /// [`discriminant_ty`].
+    ///
+    /// The validity requirements for the underlying value are undecided for this rvalue, see
+    /// [#91095]. Note too that the value of the discriminant is not the same thing as the
+    /// variant index; use [`discriminant_for_variant`] to convert.
     ///
-    /// Undefined (i.e., no effort is made to make it defined, but there’s no reason why it cannot
-    /// be defined to return, say, a 0) if ADT is not an enum.
+    /// For types defined in the source code as enums, this is well behaved. This is also well
+    /// formed for other types, but yields no particular value - there is no reason it couldn't be
+    /// defined to yield eg zero though.
+    ///
+    /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty
+    /// [#91095]: https://github.com/rust-lang/rust/issues/91095
+    /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant
     Discriminant(Place<'tcx>),
 
-    /// Creates an aggregate value, like a tuple or struct. This is
-    /// only needed because we want to distinguish `dest = Foo { x:
-    /// ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case
-    /// that `Foo` has a destructor. These rvalues can be optimized
-    /// away after type-checking and before lowering.
+    /// Creates an aggregate value, like a tuple or struct.
+    ///
+    /// This is needed because dataflow analysis needs to distinguish
+    /// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo`
+    /// has a destructor.
+    ///
+    /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Generator`. After
+    /// generator lowering, `Generator` aggregate kinds are disallowed too.
     Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>),
 
     /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
     ///
-    /// This is different a normal transmute because dataflow analysis will treat the box
-    /// as initialized but its content as uninitialized.
+    /// This is different from a normal transmute because dataflow analysis will treat the box as
+    /// initialized but its content as uninitialized. Like other pointer casts, this in general
+    /// affects alias analysis.
+    ///
+    /// Disallowed after drop elaboration.
     ShallowInitBox(Operand<'tcx>, Ty<'tcx>),
 }
 
diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs
index 965d30a7b92..afcd5db8f48 100644
--- a/compiler/rustc_middle/src/mir/spanview.rs
+++ b/compiler/rustc_middle/src/mir/spanview.rs
@@ -243,6 +243,7 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
         Assign(..) => "Assign",
         FakeRead(..) => "FakeRead",
         SetDiscriminant { .. } => "SetDiscriminant",
+        Deinit(..) => "Deinit",
         StorageLive(..) => "StorageLive",
         StorageDead(..) => "StorageDead",
         Retag(..) => "Retag",
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 51d8113840a..597ade42236 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -76,6 +76,9 @@ impl<'tcx> PlaceTy<'tcx> {
         V: ::std::fmt::Debug,
         T: ::std::fmt::Debug + Copy,
     {
+        if self.variant_index.is_some() && !matches!(elem, ProjectionElem::Field(..)) {
+            bug!("cannot use non field projection on downcasted place")
+        }
         let answer = match *elem {
             ProjectionElem::Deref => {
                 let ty = self
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index ae94bd121f9..cc08857463d 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -105,13 +105,34 @@ impl<'a> Iterator for SwitchTargetsIter<'a> {
 
 impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {}
 
+/// A note on unwinding: Panics may occur during the execution of some terminators. Depending on the
+/// `-C panic` flag, this may either cause the program to abort or the call stack to unwind. Such
+/// terminators have a `cleanup: Option<BasicBlock>` field on them. If stack unwinding occurs, then
+/// once the current function is reached, execution continues at the given basic block, if any. If
+/// `cleanup` is `None` then no cleanup is performed, and the stack continues unwinding. This is
+/// equivalent to the execution of a `Resume` terminator.
+///
+/// The basic block pointed to by a `cleanup` field must have its `cleanup` flag set. `cleanup`
+/// basic blocks have a couple restrictions:
+///  1. All `cleanup` fields in them must be `None`.
+///  2. `Return` terminators are not allowed in them. `Abort` and `Unwind` terminators are.
+///  3. All other basic blocks (in the current body) that are reachable from `cleanup` basic blocks
+///     must also be `cleanup`. This is a part of the type system and checked statically, so it is
+///     still an error to have such an edge in the CFG even if it's known that it won't be taken at
+///     runtime.
 #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
 pub enum TerminatorKind<'tcx> {
-    /// Block should have one successor in the graph; we jump there.
+    /// Block has one successor; we continue execution there.
     Goto { target: BasicBlock },
 
-    /// Operand evaluates to an integer; jump depending on its value
-    /// to one of the targets, and otherwise fallback to `otherwise`.
+    /// Switches based on the computed value.
+    ///
+    /// First, evaluates the `discr` operand. The type of the operand must be a signed or unsigned
+    /// integer, char, or bool, and must match the given type. Then, if the list of switch targets
+    /// contains the computed value, continues execution at the associated basic block. Otherwise,
+    /// continues execution at the "otherwise" basic block.
+    ///
+    /// Target values may not appear more than once.
     SwitchInt {
         /// The discriminant value being tested.
         discr: Operand<'tcx>,
@@ -124,29 +145,62 @@ pub enum TerminatorKind<'tcx> {
         targets: SwitchTargets,
     },
 
-    /// Indicates that the landing pad is finished and unwinding should
-    /// continue. Emitted by `build::scope::diverge_cleanup`.
+    /// Indicates that the landing pad is finished and that the process should continue unwinding.
+    ///
+    /// Like a return, this marks the end of this invocation of the function.
+    ///
+    /// Only permitted in cleanup blocks. `Resume` is not permitted with `-C unwind=abort` after
+    /// deaggregation runs.
     Resume,
 
-    /// Indicates that the landing pad is finished and that the process
-    /// should abort. Used to prevent unwinding for foreign items.
+    /// Indicates that the landing pad is finished and that the process should abort.
+    ///
+    /// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in
+    /// cleanup blocks.
     Abort,
 
-    /// Indicates a normal return. The return place should have
-    /// been filled in before this executes. This can occur multiple times
-    /// in different basic blocks.
+    /// Returns from the function.
+    ///
+    /// Like function calls, the exact semantics of returns in Rust are unclear. Returning very
+    /// likely at least assigns the value currently in the return place (`_0`) to the place
+    /// specified in the associated `Call` terminator in the calling function, as if assigned via
+    /// `dest = move _0`. It might additionally do other things, like have side-effects in the
+    /// aliasing model.
+    ///
+    /// If the body is a generator body, this has slightly different semantics; it instead causes a
+    /// `GeneratorState::Returned(_0)` to be created (as if by an `Aggregate` rvalue) and assigned
+    /// to the return place.
     Return,
 
     /// Indicates a terminator that can never be reached.
+    ///
+    /// Executing this terminator is UB.
     Unreachable,
 
-    /// Drop the `Place`.
+    /// The behavior of this statement differs significantly before and after drop elaboration.
+    /// After drop elaboration, `Drop` executes the drop glue for the specified place, after which
+    /// it continues execution/unwinds at the given basic blocks. It is possible that executing drop
+    /// glue is special - this would be part of Rust's memory model. (**FIXME**: due we have an
+    /// issue tracking if drop glue has any interesting semantics in addition to those of a function
+    /// call?)
+    ///
+    /// `Drop` before drop elaboration is a *conditional* execution of the drop glue. Specifically, the
+    /// `Drop` will be executed if...
+    ///
+    /// **Needs clarification**: End of that sentence. This in effect should document the exact
+    /// behavior of drop elaboration. The following sounds vaguely right, but I'm not quite sure:
+    ///
+    /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to
+    /// > the place or one of its "parents" occurred more recently than a move out of it. This does not
+    /// > consider indirect assignments.
     Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
 
-    /// Drop the `Place` and assign the new value over it. This ensures
-    /// that the assignment to `P` occurs *even if* the destructor for
-    /// place unwinds. Its semantics are best explained by the
-    /// elaboration:
+    /// 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:
     ///
     /// ```
     /// BB0 {
@@ -170,7 +224,7 @@ pub enum TerminatorKind<'tcx> {
     /// }
     /// ```
     ///
-    /// Note that DropAndReplace is eliminated as part of the `ElaborateDrops` pass.
+    /// Disallowed after drop elaboration.
     DropAndReplace {
         place: Place<'tcx>,
         value: Operand<'tcx>,
@@ -178,7 +232,16 @@ pub enum TerminatorKind<'tcx> {
         unwind: Option<BasicBlock>,
     },
 
-    /// Block ends with a call of a function.
+    /// 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
+    /// callable, meaning either a function pointer, a function type, or a closure type.
+    ///
+    /// **Needs clarification**: The exact semantics of this. Current backends rely on `move`
+    /// operands not aliasing the return place. It is unclear how this is justified in MIR, see
+    /// [#71117].
+    ///
+    /// [#71117]: https://github.com/rust-lang/rust/issues/71117
     Call {
         /// The function that’s being called.
         func: Operand<'tcx>,
@@ -187,7 +250,7 @@ pub enum TerminatorKind<'tcx> {
         /// This allows the memory occupied by "by-value" arguments to be
         /// reused across function calls without duplicating the contents.
         args: Vec<Operand<'tcx>>,
-        /// Destination for the return value. If some, the call is converging.
+        /// Destination for the return value. If none, the call necessarily diverges.
         destination: Option<(Place<'tcx>, BasicBlock)>,
         /// Cleanups to be done if the call unwinds.
         cleanup: Option<BasicBlock>,
@@ -199,8 +262,12 @@ pub enum TerminatorKind<'tcx> {
         fn_span: Span,
     },
 
-    /// Jump to the target if the condition has the expected value,
-    /// otherwise panic with a message and a cleanup target.
+    /// Evaluates the operand, which must have type `bool`. If it is not equal to `expected`,
+    /// initiates a panic. Initiating a panic corresponds to a `Call` terminator with some
+    /// unspecified constant as the function to call, all the operands stored in the `AssertMessage`
+    /// as parameters, and `None` for the destination. Keep in mind that the `cleanup` path is not
+    /// necessarily executed even in the case of a panic, for example in `-C panic=abort`. If the
+    /// assertion does not fail, execution continues at the specified basic block.
     Assert {
         cond: Operand<'tcx>,
         expected: bool,
@@ -209,7 +276,18 @@ pub enum TerminatorKind<'tcx> {
         cleanup: Option<BasicBlock>,
     },
 
-    /// A suspend point.
+    /// Marks a suspend point.
+    ///
+    /// Like `Return` terminators in generator bodies, this computes `value` and then a
+    /// `GeneratorState::Yielded(value)` as if by `Aggregate` rvalue. That value is then assigned to
+    /// the return place of the function calling this one, and execution continues in the calling
+    /// function. When next invoked with the same first argument, execution of this function
+    /// continues at the `resume` basic block, with the second argument written to the `resume_arg`
+    /// place. If the generator is dropped before then, the `drop` basic block is invoked.
+    ///
+    /// Not permitted in bodies that are not generator bodies, or after generator lowering.
+    ///
+    /// **Needs clarification**: What about the evaluation order of the `resume_arg` and `value`?
     Yield {
         /// The value to return.
         value: Operand<'tcx>,
@@ -221,11 +299,24 @@ pub enum TerminatorKind<'tcx> {
         drop: Option<BasicBlock>,
     },
 
-    /// Indicates the end of the dropping of a generator.
+    /// Indicates the end of dropping a generator.
+    ///
+    /// Semantically just a `return` (from the generators drop glue). Only permitted in the same situations
+    /// as `yield`.
+    ///
+    /// **Needs clarification**: Is that even correct? The generator drop code is always confusing
+    /// to me, because it's not even really in the current body.
+    ///
+    /// **Needs clarification**: Are there type system constraints on these terminators? Should
+    /// there be a "block type" like `cleanup` blocks for them?
     GeneratorDrop,
 
-    /// A block where control flow only ever takes one real path, but borrowck
-    /// needs to be more conservative.
+    /// A block where control flow only ever takes one real path, but borrowck needs to be more
+    /// conservative.
+    ///
+    /// At runtime this is semantically just a goto.
+    ///
+    /// Disallowed after drop elaboration.
     FalseEdge {
         /// The target normal control flow will take.
         real_target: BasicBlock,
@@ -233,9 +324,14 @@ pub enum TerminatorKind<'tcx> {
         /// practice.
         imaginary_target: BasicBlock,
     },
-    /// A terminator for blocks that only take one path in reality, but where we
-    /// reserve the right to unwind in borrowck, even if it won't happen in practice.
-    /// This can arise in infinite loops with no function calls for example.
+
+    /// A terminator for blocks that only take one path in reality, but where we reserve the right
+    /// to unwind in borrowck, even if it won't happen in practice. This can arise in infinite loops
+    /// with no function calls for example.
+    ///
+    /// At runtime this is semantically just a goto.
+    ///
+    /// Disallowed after drop elaboration.
     FalseUnwind {
         /// The target normal control flow will take.
         real_target: BasicBlock,
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index aeb0f956eb4..45b1ad6df82 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -395,10 +395,17 @@ macro_rules! make_mir_visitor {
                     StatementKind::SetDiscriminant { place, .. } => {
                         self.visit_place(
                             place,
-                            PlaceContext::MutatingUse(MutatingUseContext::Store),
+                            PlaceContext::MutatingUse(MutatingUseContext::SetDiscriminant),
                             location
                         );
                     }
+                    StatementKind::Deinit(place) => {
+                        self.visit_place(
+                            place,
+                            PlaceContext::MutatingUse(MutatingUseContext::Deinit),
+                            location
+                        )
+                    }
                     StatementKind::StorageLive(local) => {
                         self.visit_local(
                             local,
@@ -1174,6 +1181,10 @@ pub enum NonMutatingUseContext {
 pub enum MutatingUseContext {
     /// Appears as LHS of an assignment.
     Store,
+    /// Appears on `SetDiscriminant`
+    SetDiscriminant,
+    /// Appears on `Deinit`
+    Deinit,
     /// Output operand of an inline assembly block.
     AsmOutput,
     /// Destination of a call.
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index d93c9a79c65..07878defa8c 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -347,8 +347,7 @@ impl<'tcx> Ty<'tcx> {
 impl<'tcx> TyCtxt<'tcx> {
     pub fn note_and_explain_type_err(
         self,
-        // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`.
-        db: &mut Diagnostic,
+        diag: &mut Diagnostic,
         err: &TypeError<'tcx>,
         cause: &ObligationCause<'tcx>,
         sp: Span,
@@ -360,12 +359,12 @@ impl<'tcx> TyCtxt<'tcx> {
             ArgumentSorts(values, _) | Sorts(values) => {
                 match (values.expected.kind(), values.found.kind()) {
                     (ty::Closure(..), ty::Closure(..)) => {
-                        db.note("no two closures, even if identical, have the same type");
-                        db.help("consider boxing your closure and/or using it as a trait object");
+                        diag.note("no two closures, even if identical, have the same type");
+                        diag.help("consider boxing your closure and/or using it as a trait object");
                     }
                     (ty::Opaque(..), ty::Opaque(..)) => {
                         // Issue #63167
-                        db.note("distinct uses of `impl Trait` result in different opaque types");
+                        diag.note("distinct uses of `impl Trait` result in different opaque types");
                     }
                     (ty::Float(_), ty::Infer(ty::IntVar(_)))
                         if let Ok(
@@ -374,7 +373,7 @@ impl<'tcx> TyCtxt<'tcx> {
                         ) = self.sess.source_map().span_to_snippet(sp) =>
                     {
                         if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') {
-                            db.span_suggestion(
+                            diag.span_suggestion(
                                 sp,
                                 "use a float literal",
                                 format!("{}.0", snippet),
@@ -386,30 +385,30 @@ impl<'tcx> TyCtxt<'tcx> {
                         let generics = self.generics_of(body_owner_def_id);
                         let e_span = self.def_span(generics.type_param(expected, self).def_id);
                         if !sp.contains(e_span) {
-                            db.span_label(e_span, "expected type parameter");
+                            diag.span_label(e_span, "expected type parameter");
                         }
                         let f_span = self.def_span(generics.type_param(found, self).def_id);
                         if !sp.contains(f_span) {
-                            db.span_label(f_span, "found type parameter");
+                            diag.span_label(f_span, "found type parameter");
                         }
-                        db.note(
+                        diag.note(
                             "a type parameter was expected, but a different one was found; \
                              you might be missing a type parameter or trait bound",
                         );
-                        db.note(
+                        diag.note(
                             "for more information, visit \
                              https://doc.rust-lang.org/book/ch10-02-traits.html\
                              #traits-as-parameters",
                         );
                     }
                     (ty::Projection(_), ty::Projection(_)) => {
-                        db.note("an associated type was expected, but a different one was found");
+                        diag.note("an associated type was expected, but a different one was found");
                     }
                     (ty::Param(p), ty::Projection(proj)) | (ty::Projection(proj), ty::Param(p)) => {
                         let generics = self.generics_of(body_owner_def_id);
                         let p_span = self.def_span(generics.type_param(p, self).def_id);
                         if !sp.contains(p_span) {
-                            db.span_label(p_span, "this type parameter");
+                            diag.span_label(p_span, "this type parameter");
                         }
                         let hir = self.hir();
                         let mut note = true;
@@ -444,14 +443,14 @@ impl<'tcx> TyCtxt<'tcx> {
                             note = !suggest_constraining_type_param(
                                 self,
                                 generics,
-                                db,
+                                diag,
                                 &format!("{}", proj.self_ty()),
                                 &path,
                                 None,
                             );
                         }
                         if note {
-                            db.note("you might be missing a type parameter or trait bound");
+                            diag.note("you might be missing a type parameter or trait bound");
                         }
                     }
                     (ty::Param(p), ty::Dynamic(..) | ty::Opaque(..))
@@ -459,11 +458,11 @@ impl<'tcx> TyCtxt<'tcx> {
                         let generics = self.generics_of(body_owner_def_id);
                         let p_span = self.def_span(generics.type_param(p, self).def_id);
                         if !sp.contains(p_span) {
-                            db.span_label(p_span, "this type parameter");
+                            diag.span_label(p_span, "this type parameter");
                         }
-                        db.help("type parameters must be constrained to match other types");
-                        if self.sess.teach(&db.get_code().unwrap()) {
-                            db.help(
+                        diag.help("type parameters must be constrained to match other types");
+                        if self.sess.teach(&diag.get_code().unwrap()) {
+                            diag.help(
                                 "given a type parameter `T` and a method `foo`:
 ```
 trait Trait<T> { fn foo(&self) -> T; }
@@ -489,7 +488,7 @@ impl<T> Trait<T> for X {
 ```",
                             );
                         }
-                        db.note(
+                        diag.note(
                             "for more information, visit \
                              https://doc.rust-lang.org/book/ch10-02-traits.html\
                              #traits-as-parameters",
@@ -499,9 +498,9 @@ impl<T> Trait<T> for X {
                         let generics = self.generics_of(body_owner_def_id);
                         let p_span = self.def_span(generics.type_param(p, self).def_id);
                         if !sp.contains(p_span) {
-                            db.span_label(p_span, "this type parameter");
+                            diag.span_label(p_span, "this type parameter");
                         }
-                        db.help(&format!(
+                        diag.help(&format!(
                             "every closure has a distinct type and so could not always match the \
                              caller-chosen type of parameter `{}`",
                             p
@@ -511,12 +510,12 @@ impl<T> Trait<T> for X {
                         let generics = self.generics_of(body_owner_def_id);
                         let p_span = self.def_span(generics.type_param(p, self).def_id);
                         if !sp.contains(p_span) {
-                            db.span_label(p_span, "this type parameter");
+                            diag.span_label(p_span, "this type parameter");
                         }
                     }
                     (ty::Projection(proj_ty), _) => {
                         self.expected_projection(
-                            db,
+                            diag,
                             proj_ty,
                             values,
                             body_owner_def_id,
@@ -529,19 +528,19 @@ impl<T> Trait<T> for X {
                             values.found, values.expected,
                         );
                         if !(self.suggest_constraining_opaque_associated_type(
-                            db,
+                            diag,
                             &msg,
                             proj_ty,
                             values.expected,
                         ) || self.suggest_constraint(
-                            db,
+                            diag,
                             &msg,
                             body_owner_def_id,
                             proj_ty,
                             values.expected,
                         )) {
-                            db.help(&msg);
-                            db.note(
+                            diag.help(&msg);
+                            diag.note(
                                 "for more information, visit \
                                 https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
                             );
@@ -560,7 +559,7 @@ impl<T> Trait<T> for X {
             CyclicTy(ty) => {
                 // Watch out for various cases of cyclic types and try to explain.
                 if ty.is_closure() || ty.is_generator() {
-                    db.note(
+                    diag.note(
                         "closures cannot capture themselves or take themselves as argument;\n\
                          this error may be the result of a recent compiler bug-fix,\n\
                          see issue #46062 <https://github.com/rust-lang/rust/issues/46062>\n\
@@ -574,10 +573,10 @@ impl<T> Trait<T> for X {
                     .iter()
                     .filter(|attr| attr.has_name(sym::target_feature))
                     .map(|attr| attr.span);
-                db.note(
+                diag.note(
                     "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
                 );
-                db.span_labels(target_spans, "`#[target_feature]` added here");
+                diag.span_labels(target_spans, "`#[target_feature]` added here");
             }
             _ => {}
         }
@@ -585,8 +584,7 @@ impl<T> Trait<T> for X {
 
     fn suggest_constraint(
         self,
-        // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`.
-        db: &mut Diagnostic,
+        diag: &mut Diagnostic,
         msg: &str,
         body_owner_def_id: DefId,
         proj_ty: &ty::ProjectionTy<'tcx>,
@@ -623,7 +621,7 @@ impl<T> Trait<T> for X {
                         }
 
                         if self.constrain_generic_bound_associated_type_structured_suggestion(
-                            db,
+                            diag,
                             &trait_ref,
                             pred.bounds,
                             &assoc,
@@ -642,7 +640,7 @@ impl<T> Trait<T> for X {
                     {
                         // This is type param `A` in `<A as T>::Foo`.
                         return self.constrain_generic_bound_associated_type_structured_suggestion(
-                            db,
+                            diag,
                             &trait_ref,
                             param.bounds,
                             &assoc,
@@ -673,8 +671,7 @@ impl<T> Trait<T> for X {
     ///    fn that returns the type.
     fn expected_projection(
         self,
-        // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`.
-        db: &mut Diagnostic,
+        diag: &mut Diagnostic,
         proj_ty: &ty::ProjectionTy<'tcx>,
         values: &ExpectedFound<Ty<'tcx>>,
         body_owner_def_id: DefId,
@@ -712,7 +709,7 @@ impl<T> Trait<T> for X {
             // want the more general suggestion later in this method about "consider constraining
             // the associated type or calling a method that returns the associated type".
             let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type(
-                db,
+                diag,
                 assoc.container.id(),
                 current_method_ident,
                 proj_ty.item_def_id,
@@ -720,33 +717,36 @@ impl<T> Trait<T> for X {
             );
             // Possibly suggest constraining the associated type to conform to the
             // found type.
-            if self.suggest_constraint(db, &msg, body_owner_def_id, proj_ty, values.found)
+            if self.suggest_constraint(diag, &msg, body_owner_def_id, proj_ty, values.found)
                 || point_at_assoc_fn
             {
                 return;
             }
         }
 
-        self.suggest_constraining_opaque_associated_type(db, &msg, proj_ty, values.found);
+        self.suggest_constraining_opaque_associated_type(diag, &msg, proj_ty, values.found);
 
-        if self.point_at_associated_type(db, body_owner_def_id, values.found) {
+        if self.point_at_associated_type(diag, body_owner_def_id, values.found) {
             return;
         }
 
         if !impl_comparison {
             // Generic suggestion when we can't be more specific.
             if callable_scope {
-                db.help(&format!("{} or calling a method that returns `{}`", msg, values.expected));
+                diag.help(&format!(
+                    "{} or calling a method that returns `{}`",
+                    msg, values.expected
+                ));
             } else {
-                db.help(&msg);
+                diag.help(&msg);
             }
-            db.note(
+            diag.note(
                 "for more information, visit \
                  https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
             );
         }
-        if self.sess.teach(&db.get_code().unwrap()) {
-            db.help(
+        if self.sess.teach(&diag.get_code().unwrap()) {
+            diag.help(
                 "given an associated type `T` and a method `foo`:
 ```
 trait Trait {
@@ -769,8 +769,7 @@ fn foo(&self) -> Self::T { String::new() }
     /// a return type. This can occur when dealing with `TryStream` (#71035).
     fn suggest_constraining_opaque_associated_type(
         self,
-        // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`.
-        db: &mut Diagnostic,
+        diag: &mut Diagnostic,
         msg: &str,
         proj_ty: &ty::ProjectionTy<'tcx>,
         ty: Ty<'tcx>,
@@ -790,7 +789,7 @@ fn foo(&self) -> Self::T { String::new() }
             let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
 
             self.constrain_generic_bound_associated_type_structured_suggestion(
-                db,
+                diag,
                 &trait_ref,
                 opaque_hir_ty.bounds,
                 assoc,
@@ -806,8 +805,7 @@ fn foo(&self) -> Self::T { String::new() }
 
     fn point_at_methods_that_satisfy_associated_type(
         self,
-        // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`.
-        db: &mut Diagnostic,
+        diag: &mut Diagnostic,
         assoc_container_id: DefId,
         current_method_ident: Option<Symbol>,
         proj_ty_item_def_id: DefId,
@@ -854,7 +852,7 @@ fn foo(&self) -> Self::T { String::new() }
             for (sp, label) in methods.into_iter() {
                 span.push_span_label(sp, label);
             }
-            db.span_help(span, &msg);
+            diag.span_help(span, &msg);
             return true;
         }
         false
@@ -862,8 +860,7 @@ fn foo(&self) -> Self::T { String::new() }
 
     fn point_at_associated_type(
         self,
-        // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`.
-        db: &mut Diagnostic,
+        diag: &mut Diagnostic,
         body_owner_def_id: DefId,
         found: Ty<'tcx>,
     ) -> bool {
@@ -887,7 +884,7 @@ fn foo(&self) -> Self::T { String::new() }
                             if let hir::Defaultness::Default { has_value: true } = item.defaultness
                             {
                                 if self.type_of(item.id.def_id) == found {
-                                    db.span_label(
+                                    diag.span_label(
                                         item.span,
                                         "associated type defaults can't be assumed inside the \
                                             trait defining them",
@@ -907,7 +904,7 @@ fn foo(&self) -> Self::T { String::new() }
                 for item in &items[..] {
                     if let hir::AssocItemKind::Type = item.kind {
                         if self.type_of(item.id.def_id) == found {
-                            db.span_label(item.span, "expected this associated type");
+                            diag.span_label(item.span, "expected this associated type");
                             return true;
                         }
                     }
@@ -927,8 +924,7 @@ fn foo(&self) -> Self::T { String::new() }
     /// type is defined on a supertrait of the one present in the bounds.
     fn constrain_generic_bound_associated_type_structured_suggestion(
         self,
-        // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`.
-        db: &mut Diagnostic,
+        diag: &mut Diagnostic,
         trait_ref: &ty::TraitRef<'tcx>,
         bounds: hir::GenericBounds<'_>,
         assoc: &ty::AssocItem,
@@ -958,15 +954,21 @@ fn foo(&self) -> Self::T { String::new() }
             _ => return false,
         };
 
-        self.constrain_associated_type_structured_suggestion(db, span, assoc, assoc_substs, ty, msg)
+        self.constrain_associated_type_structured_suggestion(
+            diag,
+            span,
+            assoc,
+            assoc_substs,
+            ty,
+            msg,
+        )
     }
 
     /// Given a span corresponding to a bound, provide a structured suggestion to set an
     /// associated type to a given type `ty`.
     fn constrain_associated_type_structured_suggestion(
         self,
-        // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`.
-        db: &mut Diagnostic,
+        diag: &mut Diagnostic,
         span: Span,
         assoc: &ty::AssocItem,
         assoc_substs: &[ty::GenericArg<'tcx>],
@@ -984,7 +986,7 @@ fn foo(&self) -> Self::T { String::new() }
                 let item_args = self.format_generic_args(assoc_substs);
                 (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident(self), item_args, ty))
             };
-            db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
+            diag.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
             return true;
         }
         false
diff --git a/compiler/rustc_mir_dataflow/src/impls/init_locals.rs b/compiler/rustc_mir_dataflow/src/impls/init_locals.rs
index b355871d64f..584ab9718ed 100644
--- a/compiler/rustc_mir_dataflow/src/impls/init_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/init_locals.rs
@@ -77,6 +77,10 @@ impl<T> Visitor<'_> for TransferFunction<'_, T>
 where
     T: GenKill<Local>,
 {
+    // FIXME: Using `visit_local` here is a bug. For example, on `move _5.field` we mark `_5` as
+    // deinitialized, although clearly it is only partially deinitialized. This analysis is not
+    // actually used anywhere at the moment, so this is not critical, but this does need to be fixed
+    // before it starts being used again.
     fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
         use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, NonUseContext};
         match context {
@@ -87,6 +91,9 @@ where
                 | MutatingUseContext::Yield,
             ) => {}
 
+            // If it's deinitialized, it's no longer init
+            PlaceContext::MutatingUse(MutatingUseContext::Deinit) => self.trans.kill(local),
+
             // Otherwise, when a place is mutated, we must consider it possibly initialized.
             PlaceContext::MutatingUse(_) => self.trans.gen(local),
 
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 602ccec76a6..5a788c153a4 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -18,30 +18,6 @@ use crate::{AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKillAnalysis
 /// such an assignment is currently marked as a "use" of `x` in an attempt to be maximally
 /// conservative.
 ///
-/// ## Enums and `SetDiscriminant`
-///
-/// Assigning a literal value to an `enum` (e.g. `Option<i32>`), does not result in a simple
-/// assignment of the form `_1 = /*...*/` in the MIR. For example, the following assignment to `x`:
-///
-/// ```
-/// x = Some(4);
-/// ```
-///
-/// compiles to this MIR
-///
-/// ```
-/// ((_1 as Some).0: i32) = const 4_i32;
-/// discriminant(_1) = 1;
-/// ```
-///
-/// However, `MaybeLiveLocals` **does** mark `x` (`_1`) as "killed" after a statement like this.
-/// That's because it treats the `SetDiscriminant` operation as a definition of `x`, even though
-/// the writes that actually initialized the locals happened earlier.
-///
-/// This makes `MaybeLiveLocals` unsuitable for certain classes of optimization normally associated
-/// with a live variables analysis, notably dead-store elimination. It's a dirty hack, but it works
-/// okay for the generator state transform (currently the main consumer of this analysis).
-///
 /// [`MaybeBorrowedLocals`]: super::MaybeBorrowedLocals
 /// [flow-test]: https://github.com/rust-lang/rust/blob/a08c47310c7d49cbdc5d7afb38408ba519967ecd/src/test/ui/mir-dataflow/liveness-ptr.rs
 /// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis
@@ -161,7 +137,13 @@ impl DefUse {
         match context {
             PlaceContext::NonUse(_) => None,
 
-            PlaceContext::MutatingUse(MutatingUseContext::Store) => Some(DefUse::Def),
+            PlaceContext::MutatingUse(MutatingUseContext::Store | MutatingUseContext::Deinit) => {
+                Some(DefUse::Def)
+            }
+
+            // Setting the discriminant is not a use because it does no reading, but it is also not
+            // a def because it does not overwrite the whole place
+            PlaceContext::MutatingUse(MutatingUseContext::SetDiscriminant) => None,
 
             // `MutatingUseContext::Call` and `MutatingUseContext::Yield` indicate that this is the
             // destination place for a `Call` return or `Yield` resume respectively. Since this is
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index 60cde6546dc..2730e8bd49b 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -131,7 +131,8 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
 
             // If a place is assigned to in a statement, it needs storage for that statement.
             StatementKind::Assign(box (place, _))
-            | StatementKind::SetDiscriminant { box place, .. } => {
+            | StatementKind::SetDiscriminant { box place, .. }
+            | StatementKind::Deinit(box place) => {
                 trans.gen(place.local);
             }
 
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 26bbc34e780..73072464872 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -296,10 +296,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
             StatementKind::StorageDead(local) => {
                 self.gather_move(Place::from(*local));
             }
-            StatementKind::SetDiscriminant { .. } => {
+            StatementKind::SetDiscriminant { .. } | StatementKind::Deinit(..) => {
                 span_bug!(
                     stmt.source_info.span,
-                    "SetDiscriminant should not exist during borrowck"
+                    "SetDiscriminant/Deinit should not exist during borrowck"
                 );
             }
             StatementKind::Retag { .. }
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index f5d82315c4e..d1d6e7cfe2f 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -97,6 +97,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
             StatementKind::Assign(..)
             | StatementKind::FakeRead(..)
             | StatementKind::SetDiscriminant { .. }
+            | StatementKind::Deinit(..)
             | StatementKind::StorageLive(..)
             | StatementKind::StorageDead(..)
             | StatementKind::Retag { .. }
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index aa47630a26a..13b49256d48 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -897,8 +897,10 @@ impl Visitor<'_> for CanConstProp {
             // mutations of the same local via `Store`
             | MutatingUse(MutatingUseContext::Call)
             | MutatingUse(MutatingUseContext::AsmOutput)
+            | MutatingUse(MutatingUseContext::Deinit)
             // Actual store that can possibly even propagate a value
-            | MutatingUse(MutatingUseContext::Store) => {
+            | MutatingUse(MutatingUseContext::Store)
+            | MutatingUse(MutatingUseContext::SetDiscriminant) => {
                 if !self.found_assignment.insert(local) {
                     match &mut self.can_const_prop[local] {
                         // If the local can only get propagated in its own block, then we don't have
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 50400cdeac9..d6331a88c5b 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -778,7 +778,9 @@ impl Visitor<'_> for CanConstProp {
             // mutations of the same local via `Store`
             | MutatingUse(MutatingUseContext::Call)
             | MutatingUse(MutatingUseContext::AsmOutput)
+            | MutatingUse(MutatingUseContext::Deinit)
             // Actual store that can possibly even propagate a value
+            | MutatingUse(MutatingUseContext::SetDiscriminant)
             | MutatingUse(MutatingUseContext::Store) => {
                 if !self.found_assignment.insert(local) {
                     match &mut self.can_const_prop[local] {
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 5e366d7fb7d..5b7b343949c 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -827,6 +827,7 @@ pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span>
         | StatementKind::CopyNonOverlapping(..)
         | StatementKind::Assign(_)
         | StatementKind::SetDiscriminant { .. }
+        | StatementKind::Deinit(..)
         | StatementKind::Retag(_, _)
         | StatementKind::AscribeUserType(_, _) => {
             Some(statement.source_info.span)
diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs
index 79aac163550..24b626ad966 100644
--- a/compiler/rustc_mir_transform/src/deref_separator.rs
+++ b/compiler/rustc_mir_transform/src/deref_separator.rs
@@ -11,6 +11,8 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         for (i, stmt) in data.statements.iter_mut().enumerate() {
             match stmt.kind {
                 StatementKind::Assign(box (og_place, Rvalue::Ref(region, borrow_knd, place))) => {
+                    let mut place_local = place.local;
+                    let mut last_len = 0;
                     for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() {
                         if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() {
                             // The type that we are derefing.
@@ -23,15 +25,18 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                             patch.add_statement(loc, StatementKind::StorageLive(temp));
 
                             // We are adding current p_ref's projections to our
-                            // temp value.
-                            let deref_place =
-                                Place::from(p_ref.local).project_deeper(p_ref.projection, tcx);
+                            // temp value, excluding projections we already covered.
+                            let deref_place = Place::from(place_local)
+                                .project_deeper(&p_ref.projection[last_len..], tcx);
                             patch.add_assign(
                                 loc,
                                 Place::from(temp),
                                 Rvalue::Use(Operand::Move(deref_place)),
                             );
 
+                            place_local = temp;
+                            last_len = p_ref.projection.len();
+
                             // We are creating a place by using our temp value's location
                             // and copying derefed values which we need to create new statement.
                             let temp_place =
@@ -50,11 +55,6 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                             // Since our job with the temp is done it should be gone
                             let loc = Location { block: block, statement_index: i + 1 };
                             patch.add_statement(loc, StatementKind::StorageDead(temp));
-
-                            // As all projections are off the base projection, if there are
-                            // multiple derefs in the middle of projection, it might cause
-                            // unsoundness, to not let that happen we break the loop.
-                            break;
                         }
                     }
                 }
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 5d0b58e9c53..3732a308e3a 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -530,6 +530,7 @@ impl<'a> Conflicts<'a> {
             StatementKind::Assign(_) => {}
 
             StatementKind::SetDiscriminant { .. }
+            | StatementKind::Deinit(..)
             | StatementKind::StorageLive(..)
             | StatementKind::StorageDead(..)
             | StatementKind::Retag(..)
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index 04b5c4e0919..144ea0ec619 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -1441,6 +1441,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
 
             StatementKind::FakeRead(..)
             | StatementKind::SetDiscriminant { .. }
+            | StatementKind::Deinit(..)
             | StatementKind::StorageLive(_)
             | StatementKind::StorageDead(_)
             | StatementKind::Retag(..)
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 2f0673b9a76..5e6dabeba6d 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -369,6 +369,7 @@ impl<'tcx> Inliner<'tcx> {
                 match stmt.kind {
                     StatementKind::StorageLive(_)
                     | StatementKind::StorageDead(_)
+                    | StatementKind::Deinit(_)
                     | StatementKind::Nop => {}
                     _ => cost += INSTR_COST,
                 }
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 03b9ecc9596..4d214b0356c 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -50,6 +50,7 @@ impl RemoveNoopLandingPads {
 
                 StatementKind::Assign { .. }
                 | StatementKind::SetDiscriminant { .. }
+                | StatementKind::Deinit(..)
                 | StatementKind::CopyNonOverlapping(..)
                 | StatementKind::Retag { .. } => {
                     return false;
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index 785716ebecc..aaee6f491cd 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -21,7 +21,9 @@ impl<'tcx> MirPass<'tcx> for RemoveZsts {
         let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
         for block in basic_blocks.iter_mut() {
             for statement in block.statements.iter_mut() {
-                if let StatementKind::Assign(box (place, _)) = statement.kind {
+                if let StatementKind::Assign(box (place, _)) | StatementKind::Deinit(box place) =
+                    statement.kind
+                {
                     let place_ty = place.ty(local_decls, tcx).ty;
                     if !maybe_zst(place_ty) {
                         continue;
diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs
index d265720e182..33ea1c4ba2f 100644
--- a/compiler/rustc_mir_transform/src/separate_const_switch.rs
+++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs
@@ -242,6 +242,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<
             // These statements have no influence on the place
             // we are interested in
             StatementKind::FakeRead(_)
+            | StatementKind::Deinit(_)
             | StatementKind::StorageLive(_)
             | StatementKind::Retag(_, _)
             | StatementKind::AscribeUserType(_, _)
@@ -308,6 +309,7 @@ fn find_determining_place<'tcx>(
             // These statements have no influence on the place
             // we are interested in
             StatementKind::FakeRead(_)
+            | StatementKind::Deinit(_)
             | StatementKind::StorageLive(_)
             | StatementKind::StorageDead(_)
             | StatementKind::Retag(_, _)
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index d8b58ce53f8..b42e3909cf3 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -498,7 +498,8 @@ impl<'tcx> Visitor<'tcx> for UsedLocals {
                 self.visit_rvalue(rvalue, location);
             }
 
-            StatementKind::SetDiscriminant { ref place, variant_index: _ } => {
+            StatementKind::SetDiscriminant { ref place, variant_index: _ }
+            | StatementKind::Deinit(ref place) => {
                 self.visit_lhs(place, location);
             }
         }
@@ -534,9 +535,8 @@ fn remove_unused_definitions(used_locals: &mut UsedLocals, body: &mut Body<'_>)
                     }
                     StatementKind::Assign(box (place, _)) => used_locals.is_used(place.local),
 
-                    StatementKind::SetDiscriminant { ref place, .. } => {
-                        used_locals.is_used(place.local)
-                    }
+                    StatementKind::SetDiscriminant { ref place, .. }
+                    | StatementKind::Deinit(ref place) => used_locals.is_used(place.local),
                     _ => true,
                 };
 
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 5bf6f22b5d0..ca81921faed 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -970,7 +970,7 @@ impl<'a> Parser<'a> {
         }
         if fixed_crate_name {
             let fixed_name_sp = ident.span.to(idents.last().unwrap().span);
-            let mut fixed_name = format!("{}", ident.name);
+            let mut fixed_name = ident.name.to_string();
             for part in idents {
                 fixed_name.push_str(&format!("_{}", part.name));
             }
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 207ecd00e0c..b9e3adaac03 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -518,10 +518,20 @@ impl<'a> Parser<'a> {
         match arg {
             Some(arg) => {
                 if self.check(&token::Colon) | self.check(&token::Eq) {
-                    let (ident, gen_args) = match self.get_ident_from_generic_arg(arg) {
+                    let arg_span = arg.span();
+                    let (binder, ident, gen_args) = match self.get_ident_from_generic_arg(&arg) {
                         Ok(ident_gen_args) => ident_gen_args,
-                        Err(arg) => return Ok(Some(AngleBracketedArg::Arg(arg))),
+                        Err(()) => return Ok(Some(AngleBracketedArg::Arg(arg))),
                     };
+                    if binder.is_some() {
+                        // FIXME(compiler-errors): this could be improved by suggesting lifting
+                        // this up to the trait, at least before this becomes real syntax.
+                        // e.g. `Trait<for<'a> Assoc = Ty>` -> `for<'a> Trait<Assoc = Ty>`
+                        return Err(self.struct_span_err(
+                            arg_span,
+                            "`for<...>` is not allowed on associated type bounds",
+                        ));
+                    }
                     let kind = if self.eat(&token::Colon) {
                         // Parse associated type constraint bound.
 
@@ -700,18 +710,32 @@ impl<'a> Parser<'a> {
         Ok(Some(arg))
     }
 
+    /// Given a arg inside of generics, we try to destructure it as if it were the LHS in
+    /// `LHS = ...`, i.e. an associated type binding.
+    /// This returns (optionally, if they are present) any `for<'a, 'b>` binder args, the
+    /// identifier, and any GAT arguments.
     fn get_ident_from_generic_arg(
         &self,
-        gen_arg: GenericArg,
-    ) -> Result<(Ident, Option<GenericArgs>), GenericArg> {
-        if let GenericArg::Type(ty) = &gen_arg
-            && let ast::TyKind::Path(qself, path) = &ty.kind
-            && qself.is_none()
-            && path.segments.len() == 1
-        {
-            let seg = &path.segments[0];
-            return Ok((seg.ident, seg.args.as_deref().cloned()));
+        gen_arg: &GenericArg,
+    ) -> Result<(Option<Vec<ast::GenericParam>>, Ident, Option<GenericArgs>), ()> {
+        if let GenericArg::Type(ty) = gen_arg {
+            if let ast::TyKind::Path(qself, path) = &ty.kind
+                && qself.is_none()
+                && let [seg] = path.segments.as_slice()
+            {
+                return Ok((None, seg.ident, seg.args.as_deref().cloned()));
+            } else if let ast::TyKind::TraitObject(bounds, ast::TraitObjectSyntax::None) = &ty.kind
+                && let [ast::GenericBound::Trait(trait_ref, ast::TraitBoundModifier::None)] =
+                    bounds.as_slice()
+                && let [seg] = trait_ref.trait_ref.path.segments.as_slice()
+            {
+                return Ok((
+                    Some(trait_ref.bound_generic_params.clone()),
+                    seg.ident,
+                    seg.args.as_deref().cloned(),
+                ));
+            }
         }
-        Err(gen_arg)
+        Err(())
     }
 }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 609dbd1fe1b..de2229f742d 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -632,7 +632,7 @@ impl<'a> Resolver<'a> {
             VisResolutionError::Relative2018(span, path) => {
                 let mut err = self.session.struct_span_err(
                     span,
-                    "relative paths are not supported in visibilities on 2018 edition",
+                    "relative paths are not supported in visibilities in 2018 edition or later",
                 );
                 err.span_suggestion(
                     path.span,
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 1e943f0e44a..3ec63d102fa 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1875,8 +1875,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
     /// Returns whether to add `'static` lifetime to the suggested lifetime list.
     crate fn report_elision_failure(
         &mut self,
-        // FIXME(eddyb) rename this since it's no longer a `DiagnosticBuilder`.
-        db: &mut Diagnostic,
+        diag: &mut Diagnostic,
         params: &[ElisionFailureInfo],
     ) -> bool {
         let mut m = String::new();
@@ -1891,7 +1890,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
             let ElisionFailureInfo { parent, index, lifetime_count: n, have_bound_regions, span } =
                 info;
 
-            db.span_label(span, "");
+            diag.span_label(span, "");
             let help_name = if let Some(ident) =
                 parent.and_then(|body| self.tcx.hir().body(body).params[index].pat.simple_ident())
             {
@@ -1923,27 +1922,27 @@ impl<'tcx> LifetimeContext<'_, 'tcx> {
         }
 
         if len == 0 {
-            db.help(
+            diag.help(
                 "this function's return type contains a borrowed value, \
                  but there is no value for it to be borrowed from",
             );
             true
         } else if elided_len == 0 {
-            db.help(
+            diag.help(
                 "this function's return type contains a borrowed value with \
                  an elided lifetime, but the lifetime cannot be derived from \
                  the arguments",
             );
             true
         } else if elided_len == 1 {
-            db.help(&format!(
+            diag.help(&format!(
                 "this function's return type contains a borrowed value, \
                  but the signature does not say which {} it is borrowed from",
                 m
             ));
             false
         } else {
-            db.help(&format!(
+            diag.help(&format!(
                 "this function's return type contains a borrowed value, \
                  but the signature does not say whether it is borrowed from {}",
                 m
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 9881046ddfa..d70f89760a1 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -20,8 +20,8 @@ use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType};
 use rustc_errors::json::JsonEmitter;
 use rustc_errors::registry::Registry;
 use rustc_errors::{
-    fallback_fluent_bundle, fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
-    EmissionGuarantee, ErrorGuaranteed, FluentBundle, MultiSpan,
+    fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, EmissionGuarantee,
+    ErrorGuaranteed, FluentBundle, MultiSpan,
 };
 use rustc_macros::HashStable_Generic;
 pub use rustc_span::def_id::StableCrateId;
@@ -1162,6 +1162,7 @@ pub enum DiagnosticOutput {
 pub fn build_session(
     sopts: config::Options,
     local_crate_source_file: Option<PathBuf>,
+    bundle: Option<Lrc<rustc_errors::FluentBundle>>,
     registry: rustc_errors::registry::Registry,
     diagnostics_output: DiagnosticOutput,
     driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
@@ -1214,16 +1215,17 @@ pub fn build_session(
         hash_kind,
     ));
 
-    let bundle = fluent_bundle(
-        &sysroot,
-        sopts.debugging_opts.translate_lang.clone(),
-        sopts.debugging_opts.translate_additional_ftl.as_deref(),
-        sopts.debugging_opts.translate_directionality_markers,
-    )
-    .expect("failed to load fluent bundle");
     let fallback_bundle =
-        fallback_fluent_bundle(sopts.debugging_opts.translate_directionality_markers)
-            .expect("failed to load fallback fluent bundle");
+        match fallback_fluent_bundle(sopts.debugging_opts.translate_directionality_markers) {
+            Ok(bundle) => bundle,
+            Err(e) => {
+                early_error(
+                    sopts.error_format,
+                    &format!("failed to load fallback fluent bundle: {e}"),
+                );
+            }
+        };
+
     let emitter =
         default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle, write_dest);
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index ac98dd5801e..0cb70de2415 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -440,6 +440,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             }
                         }
 
+                        if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait()
+                            && predicate_is_const
+                        {
+                            err.note("`~const Drop` was renamed to `~const Destruct`");
+                            err.note("See <https://github.com/rust-lang/rust/pull/94901> for more details");
+                        }
+
                         let explanation = if let ObligationCauseCode::MainFunctionType =
                             obligation.cause.code()
                         {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index c920c80d1bb..ead1f0126c4 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1083,20 +1083,31 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         let parent_node = hir.get_parent_node(obligation.cause.body_id);
         let node = hir.find(parent_node);
         if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })) = node
-            && let body = hir.body(*body_id)
-            && let hir::ExprKind::Block(blk, _) = &body.value.kind
+            && let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind
             && sig.decl.output.span().overlaps(span)
             && blk.expr.is_none()
-            && *trait_pred.self_ty().skip_binder().kind() == ty::Tuple(ty::List::empty())
-            // FIXME(estebank): When encountering a method with a trait
-            // bound not satisfied in the return type with a body that has
-            // no return, suggest removal of semicolon on last statement.
-            // Once that is added, close #54771.
+            && trait_pred.self_ty().skip_binder().is_unit()
             && let Some(stmt) = blk.stmts.last()
-            && let hir::StmtKind::Semi(_) = stmt.kind
+            && let hir::StmtKind::Semi(expr) = stmt.kind
+            // Only suggest this if the expression behind the semicolon implements the predicate
+            && let Some(typeck_results) = self.in_progress_typeck_results
+            && let Some(ty) = typeck_results.borrow().expr_ty_opt(expr)
+            && self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, ty))
         {
-            let sp = self.tcx.sess.source_map().end_point(stmt.span);
-            err.span_label(sp, "consider removing this semicolon");
+            err.span_label(
+                expr.span,
+                &format!(
+                    "this expression has type `{}`, which implements `{}`",
+                    ty,
+                    trait_pred.print_modifiers_and_trait_path()
+                )
+            );
+            err.span_suggestion(
+                self.tcx.sess.source_map().end_point(stmt.span),
+                "remove this semicolon",
+                String::new(),
+                Applicability::MachineApplicable
+            );
             return true;
         }
         false
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index e58617b985d..6bae0f2eac9 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -2460,8 +2460,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 self.normalize_ty(ast_ty.span, array_ty)
             }
             hir::TyKind::Typeof(ref e) => {
-                tcx.sess.emit_err(TypeofReservedKeywordUsed { span: ast_ty.span });
-                tcx.type_of(tcx.hir().local_def_id(e.hir_id))
+                let ty = tcx.type_of(tcx.hir().local_def_id(e.hir_id));
+                let span = ast_ty.span;
+                tcx.sess.emit_err(TypeofReservedKeywordUsed {
+                    span,
+                    ty,
+                    opt_sugg: Some((span, Applicability::MachineApplicable))
+                        .filter(|_| ty.is_suggestable()),
+                });
+
+                ty
             }
             hir::TyKind::Infer => {
                 // Infer also appears as the type of arguments or return
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 6091b8fee00..47292b3e339 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -55,6 +55,7 @@ use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
 pub struct CastCheck<'tcx> {
     expr: &'tcx hir::Expr<'tcx>,
     expr_ty: Ty<'tcx>,
+    expr_span: Span,
     cast_ty: Ty<'tcx>,
     cast_span: Span,
     span: Span,
@@ -207,7 +208,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         cast_span: Span,
         span: Span,
     ) -> Result<CastCheck<'tcx>, ErrorGuaranteed> {
-        let check = CastCheck { expr, expr_ty, cast_ty, cast_span, span };
+        let expr_span = expr.span.find_ancestor_inside(span).unwrap_or(expr.span);
+        let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span };
 
         // For better error messages, check for some obviously unsized
         // cases now. We do a more thorough check at the end, once
@@ -240,15 +242,15 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     error_span,
                     format!("cannot cast `{}` as `{}`", fcx.ty_to_string(self.expr_ty), cast_ty),
                 );
-                if let Ok(snippet) = fcx.sess().source_map().span_to_snippet(self.expr.span) {
+                if let Ok(snippet) = fcx.sess().source_map().span_to_snippet(self.expr_span) {
                     err.span_suggestion(
-                        self.expr.span,
+                        self.expr_span,
                         "dereference the expression",
                         format!("*{}", snippet),
                         Applicability::MaybeIncorrect,
                     );
                 } else {
-                    err.span_help(self.expr.span, "dereference the expression with `*`");
+                    err.span_help(self.expr_span, "dereference the expression with `*`");
                 }
                 err.emit();
             }
@@ -315,7 +317,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     struct_span_err!(fcx.tcx.sess, self.span, E0054, "cannot cast as `bool`");
 
                 if self.expr_ty.is_numeric() {
-                    match fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
+                    match fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
                         Ok(snippet) => {
                             err.span_suggestion(
                                 self.span,
@@ -440,7 +442,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 }
                 if sugg_mutref {
                     err.span_label(self.span, "invalid cast");
-                    err.span_note(self.expr.span, "this reference is immutable");
+                    err.span_note(self.expr_span, "this reference is immutable");
                     err.span_note(self.cast_span, "trying to cast to a mutable reference type");
                 } else if let Some((sugg, remove_cast)) = sugg {
                     err.span_label(self.span, "invalid cast");
@@ -449,7 +451,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                         .tcx
                         .sess
                         .source_map()
-                        .span_to_snippet(self.expr.span)
+                        .span_to_snippet(self.expr_span)
                         .map_or(false, |snip| snip.starts_with('('));
 
                     // Very crude check to see whether the expression must be wrapped
@@ -458,14 +460,14 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     let needs_parens =
                         !has_parens && matches!(self.expr.kind, hir::ExprKind::Cast(..));
 
-                    let mut suggestion = vec![(self.expr.span.shrink_to_lo(), sugg)];
+                    let mut suggestion = vec![(self.expr_span.shrink_to_lo(), sugg)];
                     if needs_parens {
                         suggestion[0].1 += "(";
-                        suggestion.push((self.expr.span.shrink_to_hi(), ")".to_string()));
+                        suggestion.push((self.expr_span.shrink_to_hi(), ")".to_string()));
                     }
                     if remove_cast {
                         suggestion.push((
-                            self.expr.span.shrink_to_hi().to(self.cast_span),
+                            self.expr_span.shrink_to_hi().to(self.cast_span),
                             String::new(),
                         ));
                     }
@@ -481,7 +483,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 ) {
                     let mut label = true;
                     // Check `impl From<self.expr_ty> for self.cast_ty {}` for accurate suggestion:
-                    if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
+                    if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
                         if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From) {
                             let ty = fcx.resolve_vars_if_possible(self.cast_ty);
                             // Erase regions to avoid panic in `prove_value` when calling
@@ -550,7 +552,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
 
                 if fcx.tcx.sess.is_nightly_build() {
                     err.span_label(
-                        self.expr.span,
+                        self.expr_span,
                         "consider casting this expression to `*const ()`, \
                         then using `core::ptr::from_raw_parts`",
                     );
@@ -651,7 +653,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 }
             }
             _ => {
-                err.span_help(self.expr.span, "consider using a box or reference as appropriate");
+                err.span_help(self.expr_span, "consider using a box or reference as appropriate");
             }
         }
         err.emit()
@@ -685,7 +687,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
 
     #[instrument(skip(fcx), level = "debug")]
     pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
-        self.expr_ty = fcx.structurally_resolved_type(self.expr.span, self.expr_ty);
+        self.expr_ty = fcx.structurally_resolved_type(self.expr_span, self.expr_ty);
         self.cast_ty = fcx.structurally_resolved_type(self.cast_span, self.cast_ty);
 
         debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);
@@ -741,7 +743,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     ty::FnDef(..) => {
                         // Attempt a coercion to a fn pointer type.
                         let f = fcx.normalize_associated_types_in(
-                            self.expr.span,
+                            self.expr_span,
                             self.expr_ty.fn_sig(fcx.tcx),
                         );
                         let res = fcx.try_coerce(
@@ -997,7 +999,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 ));
 
                 let msg = "use `.addr()` to obtain the address of a pointer";
-                if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
+                if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
                     let scalar_cast = match t_c {
                         ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(),
                         _ => format!(" as {}", self.cast_ty),
@@ -1012,7 +1014,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     err.help(msg);
                 }
                 err.help(
-                    "if you can't comply with strict provenance and need to expose the pointer\
+                    "if you can't comply with strict provenance and need to expose the pointer \
                     provenance you can use `.expose_addr()` instead"
                 );
 
@@ -1027,13 +1029,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             self.expr.hir_id,
             self.span,
             |err| {
-
                 let mut err = err.build(&format!(
                     "strict provenance disallows casting integer `{}` to pointer `{}`",
                     self.expr_ty, self.cast_ty
                 ));
                 let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address";
-                if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
+                if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
                     err.span_suggestion(
                         self.span,
                         msg,
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 1cc1460750a..f6a5243274c 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -936,7 +936,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             } else {
                 err.span_suggestion_short(
                     span_semi,
-                    "consider removing this semicolon",
+                    "remove this semicolon",
                     String::new(),
                     Applicability::MachineApplicable,
                 );
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index b2be70e707d..f9664a9b991 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -816,16 +816,69 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
         hir::GenericParamKind::Const { ty: hir_ty, default: _ } => {
             let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id));
 
-            let err_ty_str;
-            let mut is_ptr = true;
-            let err = if tcx.features().adt_const_params {
-                match ty.peel_refs().kind() {
+            if tcx.features().adt_const_params {
+                let err = match ty.peel_refs().kind() {
                     ty::FnPtr(_) => Some("function pointers"),
                     ty::RawPtr(_) => Some("raw pointers"),
                     _ => None,
+                };
+
+                if let Some(unsupported_type) = err {
+                    tcx.sess.span_err(
+                        hir_ty.span,
+                        &format!(
+                            "using {} as const generic parameters is forbidden",
+                            unsupported_type
+                        ),
+                    );
+                }
+
+                if traits::search_for_structural_match_violation(param.span, tcx, ty).is_some() {
+                    // We use the same error code in both branches, because this is really the same
+                    // issue: we just special-case the message for type parameters to make it
+                    // clearer.
+                    if let ty::Param(_) = ty.peel_refs().kind() {
+                        // Const parameters may not have type parameters as their types,
+                        // because we cannot be sure that the type parameter derives `PartialEq`
+                        // and `Eq` (just implementing them is not enough for `structural_match`).
+                        struct_span_err!(
+                            tcx.sess,
+                            hir_ty.span,
+                            E0741,
+                            "`{}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
+                            used as the type of a const parameter",
+                            ty,
+                        )
+                        .span_label(
+                            hir_ty.span,
+                            format!("`{}` may not derive both `PartialEq` and `Eq`", ty),
+                        )
+                        .note(
+                            "it is not currently possible to use a type parameter as the type of a \
+                            const parameter",
+                        )
+                        .emit();
+                    } else {
+                        struct_span_err!(
+                            tcx.sess,
+                            hir_ty.span,
+                            E0741,
+                            "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
+                            the type of a const parameter",
+                            ty,
+                        )
+                        .span_label(
+                            hir_ty.span,
+                            format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty),
+                        )
+                        .emit();
+                    }
                 }
             } else {
-                match ty.kind() {
+                let err_ty_str;
+                let mut is_ptr = true;
+
+                let err = match ty.kind() {
                     ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
                     ty::FnPtr(_) => Some("function pointers"),
                     ty::RawPtr(_) => Some("raw pointers"),
@@ -834,74 +887,33 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
                         err_ty_str = format!("`{}`", ty);
                         Some(err_ty_str.as_str())
                     }
-                }
-            };
-            if let Some(unsupported_type) = err {
-                if is_ptr {
-                    tcx.sess.span_err(
-                        hir_ty.span,
-                        &format!(
-                            "using {} as const generic parameters is forbidden",
-                            unsupported_type
-                        ),
-                    );
-                } else {
-                    let mut err = tcx.sess.struct_span_err(
-                        hir_ty.span,
-                        &format!(
-                            "{} is forbidden as the type of a const generic parameter",
-                            unsupported_type
-                        ),
-                    );
-                    err.note("the only supported types are integers, `bool` and `char`");
-                    if tcx.sess.is_nightly_build() {
-                        err.help(
+                };
+
+                if let Some(unsupported_type) = err {
+                    if is_ptr {
+                        tcx.sess.span_err(
+                            hir_ty.span,
+                            &format!(
+                                "using {} as const generic parameters is forbidden",
+                                unsupported_type
+                            ),
+                        );
+                    } else {
+                        let mut err = tcx.sess.struct_span_err(
+                            hir_ty.span,
+                            &format!(
+                                "{} is forbidden as the type of a const generic parameter",
+                                unsupported_type
+                            ),
+                        );
+                        err.note("the only supported types are integers, `bool` and `char`");
+                        if tcx.sess.is_nightly_build() {
+                            err.help(
                             "more complex types are supported with `#![feature(adt_const_params)]`",
                         );
+                        }
+                        err.emit();
                     }
-                    err.emit();
-                }
-            };
-
-            if traits::search_for_structural_match_violation(param.span, tcx, ty).is_some() {
-                // We use the same error code in both branches, because this is really the same
-                // issue: we just special-case the message for type parameters to make it
-                // clearer.
-                if let ty::Param(_) = ty.peel_refs().kind() {
-                    // Const parameters may not have type parameters as their types,
-                    // because we cannot be sure that the type parameter derives `PartialEq`
-                    // and `Eq` (just implementing them is not enough for `structural_match`).
-                    struct_span_err!(
-                        tcx.sess,
-                        hir_ty.span,
-                        E0741,
-                        "`{}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
-                            used as the type of a const parameter",
-                        ty,
-                    )
-                    .span_label(
-                        hir_ty.span,
-                        format!("`{}` may not derive both `PartialEq` and `Eq`", ty),
-                    )
-                    .note(
-                        "it is not currently possible to use a type parameter as the type of a \
-                            const parameter",
-                    )
-                    .emit();
-                } else {
-                    struct_span_err!(
-                        tcx.sess,
-                        hir_ty.span,
-                        E0741,
-                        "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
-                            the type of a const parameter",
-                        ty,
-                    )
-                    .span_label(
-                        hir_ty.span,
-                        format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty),
-                    )
-                    .emit();
                 }
             }
         }
diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs
index 0b78aea9f05..1088be5f566 100644
--- a/compiler/rustc_typeck/src/errors.rs
+++ b/compiler/rustc_typeck/src/errors.rs
@@ -1,5 +1,7 @@
 //! Errors emitted by typeck.
+use rustc_errors::Applicability;
 use rustc_macros::SessionDiagnostic;
+use rustc_middle::ty::Ty;
 use rustc_span::{symbol::Ident, Span, Symbol};
 
 #[derive(SessionDiagnostic)]
@@ -127,10 +129,13 @@ pub struct FunctionalRecordUpdateOnNonStruct {
 
 #[derive(SessionDiagnostic)]
 #[error(code = "E0516", slug = "typeck-typeof-reserved-keyword-used")]
-pub struct TypeofReservedKeywordUsed {
+pub struct TypeofReservedKeywordUsed<'tcx> {
+    pub ty: Ty<'tcx>,
     #[primary_span]
     #[label]
     pub span: Span,
+    #[suggestion_verbose(message = "suggestion", code = "{ty}")]
+    pub opt_sugg: Option<(Span, Applicability)>,
 }
 
 #[derive(SessionDiagnostic)]
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index e6faf1df3a8..639e7f213ea 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -1192,17 +1192,25 @@ impl<T: Default> Default for Box<T> {
 
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Default for Box<[T]> {
+#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
+impl<T> const Default for Box<[T]> {
     fn default() -> Self {
-        Box::<[T; 0]>::new([])
+        let ptr: Unique<[T]> = Unique::<[T; 0]>::dangling();
+        Box(ptr, Global)
     }
 }
 
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "default_box_extra", since = "1.17.0")]
-impl Default for Box<str> {
+#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
+impl const Default for Box<str> {
     fn default() -> Self {
-        unsafe { from_boxed_utf8_unchecked(Default::default()) }
+        // SAFETY: This is the same as `Unique::cast<U>` but with an unsized `U = str`.
+        let ptr: Unique<str> = unsafe {
+            let bytes: Unique<[u8]> = Unique::<[u8; 0]>::dangling();
+            Unique::new_unchecked(bytes.as_ptr() as *mut str)
+        };
+        Box(ptr, Global)
     }
 }
 
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index dcae58ae590..488671d8d8d 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -2593,14 +2593,15 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// ```
     ///
     /// If you want to insert an item to a sorted deque, while maintaining
-    /// sort order:
+    /// sort order, consider using [`partition_point`]:
     ///
     /// ```
     /// use std::collections::VecDeque;
     ///
     /// let mut deque: VecDeque<_> = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
     /// let num = 42;
-    /// let idx = deque.binary_search(&num).unwrap_or_else(|x| x);
+    /// let idx = deque.partition_point(|&x| x < num);
+    /// // The above is equivalent to `let idx = deque.binary_search(&num).unwrap_or_else(|x| x);`
     /// deque.insert(idx, num);
     /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
     /// ```
@@ -2744,6 +2745,19 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// assert!(deque.iter().take(i).all(|&x| x < 5));
     /// assert!(deque.iter().skip(i).all(|&x| !(x < 5)));
     /// ```
+    ///
+    /// If you want to insert an item to a sorted deque, while maintaining
+    /// sort order:
+    ///
+    /// ```
+    /// use std::collections::VecDeque;
+    ///
+    /// let mut deque: VecDeque<_> = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
+    /// let num = 42;
+    /// let idx = deque.partition_point(|&x| x < num);
+    /// deque.insert(idx, num);
+    /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
+    /// ```
     #[stable(feature = "vecdeque_binary_search", since = "1.54.0")]
     pub fn partition_point<P>(&self, mut pred: P) -> usize
     where
diff --git a/library/alloc/tests/const_fns.rs b/library/alloc/tests/const_fns.rs
index f448b3eb7c3..49b837becbc 100644
--- a/library/alloc/tests/const_fns.rs
+++ b/library/alloc/tests/const_fns.rs
@@ -6,6 +6,9 @@ pub const MY_VEC2: Vec<usize> = Default::default();
 pub const MY_STRING: String = String::new();
 pub const MY_STRING2: String = Default::default();
 
+pub const MY_BOXED_SLICE: Box<[usize]> = Default::default();
+pub const MY_BOXED_STR: Box<str> = Default::default();
+
 use std::collections::{BTreeMap, BTreeSet};
 
 pub const MY_BTREEMAP: BTreeMap<usize, usize> = BTreeMap::new();
@@ -23,6 +26,9 @@ fn test_const() {
     assert_eq!(MY_VEC, MY_VEC2);
     assert_eq!(MY_STRING, MY_STRING2);
 
+    assert_eq!(MY_VEC, *MY_BOXED_SLICE);
+    assert_eq!(MY_STRING, *MY_BOXED_STR);
+
     assert_eq!(MAP_LEN, 0);
     assert_eq!(SET_LEN, 0);
     assert!(MAP_IS_EMPTY && SET_IS_EMPTY);
diff --git a/library/alloc/tests/thin_box.rs b/library/alloc/tests/thin_box.rs
index 0fe6aaa4d00..51d2e9324bf 100644
--- a/library/alloc/tests/thin_box.rs
+++ b/library/alloc/tests/thin_box.rs
@@ -1,5 +1,5 @@
-use alloc::boxed::ThinBox;
 use core::mem::size_of;
+use std::boxed::ThinBox;
 
 #[test]
 fn want_niche_optimization() {
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs
index 612e366cedf..6ec178b7bd5 100644
--- a/library/core/src/alloc/layout.rs
+++ b/library/core/src/alloc/layout.rs
@@ -30,7 +30,7 @@ const fn size_align<T>() -> (usize, usize) {
 #[lang = "alloc_layout"]
 pub struct Layout {
     // size of the requested block of memory, measured in bytes.
-    size_: usize,
+    size: usize,
 
     // alignment of the requested block of memory, measured in bytes.
     // we ensure that this is always a power-of-two, because API's
@@ -39,7 +39,7 @@ pub struct Layout {
     //
     // (However, we do not analogously require `align >= sizeof(void*)`,
     //  even though that is *also* a requirement of `posix_memalign`.)
-    align_: ValidAlign,
+    align: ValidAlign,
 }
 
 impl Layout {
@@ -97,7 +97,7 @@ impl Layout {
     #[inline]
     pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
         // SAFETY: the caller must ensure that `align` is a power of two.
-        Layout { size_: size, align_: unsafe { ValidAlign::new_unchecked(align) } }
+        Layout { size, align: unsafe { ValidAlign::new_unchecked(align) } }
     }
 
     /// The minimum size in bytes for a memory block of this layout.
@@ -106,7 +106,7 @@ impl Layout {
     #[must_use]
     #[inline]
     pub const fn size(&self) -> usize {
-        self.size_
+        self.size
     }
 
     /// The minimum byte alignment for a memory block of this layout.
@@ -116,7 +116,7 @@ impl Layout {
                   without modifying the layout"]
     #[inline]
     pub const fn align(&self) -> usize {
-        self.align_.as_nonzero().get()
+        self.align.as_nonzero().get()
     }
 
     /// Constructs a `Layout` suitable for holding a value of type `T`.
diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs
index 4ee0310b361..778f06aeb63 100644
--- a/library/core/src/char/convert.rs
+++ b/library/core/src/char/convert.rs
@@ -6,52 +6,10 @@ use crate::fmt;
 use crate::mem::transmute;
 use crate::str::FromStr;
 
-/// Converts a `u32` to a `char`.
-///
-/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with
-/// `as`:
-///
-/// ```
-/// let c = '💯';
-/// let i = c as u32;
-///
-/// assert_eq!(128175, i);
-/// ```
-///
-/// However, the reverse is not true: not all valid [`u32`]s are valid
-/// [`char`]s. `from_u32()` will return `None` if the input is not a valid value
-/// for a [`char`].
-///
-/// For an unsafe version of this function which ignores these checks, see
-/// [`from_u32_unchecked`].
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::char;
-///
-/// let c = char::from_u32(0x2764);
-///
-/// assert_eq!(Some('❤'), c);
-/// ```
-///
-/// Returning `None` when the input is not a valid [`char`]:
-///
-/// ```
-/// use std::char;
-///
-/// let c = char::from_u32(0x110000);
-///
-/// assert_eq!(None, c);
-/// ```
-#[doc(alias = "chr")]
+/// Converts a `u32` to a `char`. See [`char::from_u32`].
 #[must_use]
 #[inline]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
-pub const fn from_u32(i: u32) -> Option<char> {
+pub(super) const fn from_u32(i: u32) -> Option<char> {
     // FIXME: once Result::ok is const fn, use it here
     match char_try_from_u32(i) {
         Ok(c) => Some(c),
@@ -59,44 +17,11 @@ pub const fn from_u32(i: u32) -> Option<char> {
     }
 }
 
-/// Converts a `u32` to a `char`, ignoring validity.
-///
-/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with
-/// `as`:
-///
-/// ```
-/// let c = '💯';
-/// let i = c as u32;
-///
-/// assert_eq!(128175, i);
-/// ```
-///
-/// However, the reverse is not true: not all valid [`u32`]s are valid
-/// [`char`]s. `from_u32_unchecked()` will ignore this, and blindly cast to
-/// [`char`], possibly creating an invalid one.
-///
-/// # Safety
-///
-/// This function is unsafe, as it may construct invalid `char` values.
-///
-/// For a safe version of this function, see the [`from_u32`] function.
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::char;
-///
-/// let c = unsafe { char::from_u32_unchecked(0x2764) };
-///
-/// assert_eq!('❤', c);
-/// ```
+/// Converts a `u32` to a `char`, ignoring validity. See [`char::from_u32_unchecked`].
+#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
 #[inline]
 #[must_use]
-#[stable(feature = "char_from_unchecked", since = "1.5.0")]
-#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
-pub const unsafe fn from_u32_unchecked(i: u32) -> char {
+pub(super) const unsafe fn from_u32_unchecked(i: u32) -> char {
     // SAFETY: the caller must guarantee that `i` is a valid char value.
     if cfg!(debug_assertions) { char::from_u32(i).unwrap() } else { unsafe { transmute(i) } }
 }
@@ -317,60 +242,10 @@ impl fmt::Display for CharTryFromError {
     }
 }
 
-/// Converts a digit in the given radix to a `char`.
-///
-/// A 'radix' here is sometimes also called a 'base'. A radix of two
-/// indicates a binary number, a radix of ten, decimal, and a radix of
-/// sixteen, hexadecimal, to give some common values. Arbitrary
-/// radices are supported.
-///
-/// `from_digit()` will return `None` if the input is not a digit in
-/// the given radix.
-///
-/// # Panics
-///
-/// Panics if given a radix larger than 36.
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::char;
-///
-/// let c = char::from_digit(4, 10);
-///
-/// assert_eq!(Some('4'), c);
-///
-/// // Decimal 11 is a single digit in base 16
-/// let c = char::from_digit(11, 16);
-///
-/// assert_eq!(Some('b'), c);
-/// ```
-///
-/// Returning `None` when the input is not a digit:
-///
-/// ```
-/// use std::char;
-///
-/// let c = char::from_digit(20, 10);
-///
-/// assert_eq!(None, c);
-/// ```
-///
-/// Passing a large radix, causing a panic:
-///
-/// ```should_panic
-/// use std::char;
-///
-/// // this panics
-/// let c = char::from_digit(1, 37);
-/// ```
+/// Converts a digit in the given radix to a `char`. See [`char::from_digit`].
 #[inline]
 #[must_use]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
-pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
+pub(super) const fn from_digit(num: u32, radix: u32) -> Option<char> {
     if radix > 36 {
         panic!("from_digit: radix is too high (maximum 36)");
     }
diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs
index 794c9c13cc3..71297acd171 100644
--- a/library/core/src/char/decode.rs
+++ b/library/core/src/char/decode.rs
@@ -30,54 +30,9 @@ pub struct DecodeUtf16Error {
 }
 
 /// Creates an iterator over the UTF-16 encoded code points in `iter`,
-/// returning unpaired surrogates as `Err`s.
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::char::decode_utf16;
-///
-/// // 𝄞mus<invalid>ic<invalid>
-/// let v = [
-///     0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834,
-/// ];
-///
-/// assert_eq!(
-///     decode_utf16(v.iter().cloned())
-///         .map(|r| r.map_err(|e| e.unpaired_surrogate()))
-///         .collect::<Vec<_>>(),
-///     vec![
-///         Ok('𝄞'),
-///         Ok('m'), Ok('u'), Ok('s'),
-///         Err(0xDD1E),
-///         Ok('i'), Ok('c'),
-///         Err(0xD834)
-///     ]
-/// );
-/// ```
-///
-/// A lossy decoder can be obtained by replacing `Err` results with the replacement character:
-///
-/// ```
-/// use std::char::{decode_utf16, REPLACEMENT_CHARACTER};
-///
-/// // 𝄞mus<invalid>ic<invalid>
-/// let v = [
-///     0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834,
-/// ];
-///
-/// assert_eq!(
-///     decode_utf16(v.iter().cloned())
-///        .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
-///        .collect::<String>(),
-///     "𝄞mus�ic�"
-/// );
-/// ```
-#[stable(feature = "decode_utf16", since = "1.9.0")]
+/// returning unpaired surrogates as `Err`s. See [`char::decode_utf16`].
 #[inline]
-pub fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::IntoIter> {
+pub(super) fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::IntoIter> {
     DecodeUtf16 { iter: iter.into_iter(), buf: None }
 }
 
diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs
index 9364ac4f3ec..0df23e7bbe6 100644
--- a/library/core/src/char/mod.rs
+++ b/library/core/src/char/mod.rs
@@ -23,18 +23,12 @@ mod decode;
 mod methods;
 
 // stable re-exports
-#[stable(feature = "char_from_unchecked", since = "1.5.0")]
-pub use self::convert::from_u32_unchecked;
 #[stable(feature = "try_from", since = "1.34.0")]
 pub use self::convert::CharTryFromError;
 #[stable(feature = "char_from_str", since = "1.20.0")]
 pub use self::convert::ParseCharError;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::convert::{from_digit, from_u32};
 #[stable(feature = "decode_utf16", since = "1.9.0")]
-pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error};
-#[stable(feature = "unicode_version", since = "1.45.0")]
-pub use crate::unicode::UNICODE_VERSION;
+pub use self::decode::{DecodeUtf16, DecodeUtf16Error};
 
 // perma-unstable re-exports
 #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
@@ -89,30 +83,57 @@ const MAX_THREE_B: u32 = 0x10000;
     Cn  Unassigned              a reserved unassigned code point or a noncharacter
 */
 
-/// The highest valid code point a `char` can have, `'\u{10FFFF}'`.
-///
-/// # Examples
-///
-/// ```
-/// # fn something_which_returns_char() -> char { 'a' }
-/// let c: char = something_which_returns_char();
-/// assert!(c <= char::MAX);
-///
-/// let value_at_max = char::MAX as u32;
-/// assert_eq!(char::from_u32(value_at_max), Some('\u{10FFFF}'));
-/// assert_eq!(char::from_u32(value_at_max + 1), None);
-/// ```
+/// The highest valid code point a `char` can have, `'\u{10FFFF}'`. Use [`char::MAX`] instead.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub const MAX: char = char::MAX;
 
 /// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a
-/// decoding error.
-///
-/// It can occur, for example, when giving ill-formed UTF-8 bytes to
-/// [`String::from_utf8_lossy`](../../std/string/struct.String.html#method.from_utf8_lossy).
+/// decoding error. Use [`char::REPLACEMENT_CHARACTER`] instead.
 #[stable(feature = "decode_utf16", since = "1.9.0")]
 pub const REPLACEMENT_CHARACTER: char = char::REPLACEMENT_CHARACTER;
 
+/// The version of [Unicode](https://www.unicode.org/) that the Unicode parts of
+/// `char` and `str` methods are based on. Use [`char::UNICODE_VERSION`] instead.
+#[stable(feature = "unicode_version", since = "1.45.0")]
+pub const UNICODE_VERSION: (u8, u8, u8) = char::UNICODE_VERSION;
+
+/// Creates an iterator over the UTF-16 encoded code points in `iter`, returning
+/// unpaired surrogates as `Err`s. Use [`char::decode_utf16`] instead.
+#[stable(feature = "decode_utf16", since = "1.9.0")]
+#[inline]
+pub fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::IntoIter> {
+    self::decode::decode_utf16(iter)
+}
+
+/// Converts a `u32` to a `char`. Use [`char::from_u32`] instead.
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
+#[must_use]
+#[inline]
+pub const fn from_u32(i: u32) -> Option<char> {
+    self::convert::from_u32(i)
+}
+
+/// Converts a `u32` to a `char`, ignoring validity. Use [`char::from_u32_unchecked`].
+/// instead.
+#[stable(feature = "char_from_unchecked", since = "1.5.0")]
+#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
+#[must_use]
+#[inline]
+pub const unsafe fn from_u32_unchecked(i: u32) -> char {
+    // SAFETY: the safety contract must be upheld by the caller.
+    unsafe { self::convert::from_u32_unchecked(i) }
+}
+
+/// Converts a digit in the given radix to a `char`. Use [`char::from_digit`] instead.
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
+#[must_use]
+#[inline]
+pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
+    self::convert::from_digit(num, radix)
+}
+
 /// Returns an iterator that yields the hexadecimal Unicode escape of a
 /// character, as `char`s.
 ///
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 98c9bf556bb..f45b73b0533 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -5,6 +5,7 @@
 use crate::ascii;
 use crate::intrinsics;
 use crate::mem;
+use crate::ops::{Add, Mul, Sub};
 use crate::str::FromStr;
 
 // Used because the `?` operator is not allowed in a const context.
@@ -954,9 +955,10 @@ pub enum FpCategory {
 }
 
 #[doc(hidden)]
-trait FromStrRadixHelper: PartialOrd + Copy {
-    fn min_value() -> Self;
-    fn max_value() -> Self;
+trait FromStrRadixHelper:
+    PartialOrd + Copy + Add<Output = Self> + Sub<Output = Self> + Mul<Output = Self>
+{
+    const MIN: Self;
     fn from_u32(u: u32) -> Self;
     fn checked_mul(&self, other: u32) -> Option<Self>;
     fn checked_sub(&self, other: u32) -> Option<Self>;
@@ -976,12 +978,9 @@ macro_rules! from_str_radix_int_impl {
 }
 from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 }
 
-macro_rules! doit {
+macro_rules! impl_helper_for {
     ($($t:ty)*) => ($(impl FromStrRadixHelper for $t {
-        #[inline]
-        fn min_value() -> Self { Self::MIN }
-        #[inline]
-        fn max_value() -> Self { Self::MAX }
+        const MIN: Self = Self::MIN;
         #[inline]
         fn from_u32(u: u32) -> Self { u as Self }
         #[inline]
@@ -998,7 +997,18 @@ macro_rules! doit {
         }
     })*)
 }
-doit! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
+impl_helper_for! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
+
+/// Determins if a string of text of that length of that radix could be guaranteed to be
+/// stored in the given type T.
+/// Note that if the radix is known to the compiler, it is just the check of digits.len that
+/// is done at runtime.
+#[doc(hidden)]
+#[inline(always)]
+#[unstable(issue = "none", feature = "std_internals")]
+pub fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool {
+    radix <= 16 && digits.len() <= mem::size_of::<T>() * 2 - is_signed_ty as usize
+}
 
 fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, ParseIntError> {
     use self::IntErrorKind::*;
@@ -1014,7 +1024,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
         return Err(PIE { kind: Empty });
     }
 
-    let is_signed_ty = T::from_u32(0) > T::min_value();
+    let is_signed_ty = T::from_u32(0) > T::MIN;
 
     // all valid digits are ascii, so we will just iterate over the utf8 bytes
     // and cast them to chars. .to_digit() will safely return None for anything
@@ -1032,38 +1042,56 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
     };
 
     let mut result = T::from_u32(0);
-    if is_positive {
-        // The number is positive
-        for &c in digits {
-            let x = match (c as char).to_digit(radix) {
-                Some(x) => x,
-                None => return Err(PIE { kind: InvalidDigit }),
-            };
-            result = match result.checked_mul(radix) {
-                Some(result) => result,
-                None => return Err(PIE { kind: PosOverflow }),
-            };
-            result = match result.checked_add(x) {
-                Some(result) => result,
-                None => return Err(PIE { kind: PosOverflow }),
+
+    if can_not_overflow::<T>(radix, is_signed_ty, digits) {
+        // If the len of the str is short compared to the range of the type
+        // we are parsing into, then we can be certain that an overflow will not occur.
+        // This bound is when `radix.pow(digits.len()) - 1 <= T::MAX` but the condition
+        // above is a faster (conservative) approximation of this.
+        //
+        // Consider radix 16 as it has the highest information density per digit and will thus overflow the earliest:
+        // `u8::MAX` is `ff` - any str of len 2 is guaranteed to not overflow.
+        // `i8::MAX` is `7f` - only a str of len 1 is guaranteed to not overflow.
+        macro_rules! run_unchecked_loop {
+            ($unchecked_additive_op:expr) => {
+                for &c in digits {
+                    result = result * T::from_u32(radix);
+                    let x = (c as char).to_digit(radix).ok_or(PIE { kind: InvalidDigit })?;
+                    result = $unchecked_additive_op(result, T::from_u32(x));
+                }
             };
         }
+        if is_positive {
+            run_unchecked_loop!(<T as core::ops::Add>::add)
+        } else {
+            run_unchecked_loop!(<T as core::ops::Sub>::sub)
+        };
     } else {
-        // The number is negative
-        for &c in digits {
-            let x = match (c as char).to_digit(radix) {
-                Some(x) => x,
-                None => return Err(PIE { kind: InvalidDigit }),
-            };
-            result = match result.checked_mul(radix) {
-                Some(result) => result,
-                None => return Err(PIE { kind: NegOverflow }),
-            };
-            result = match result.checked_sub(x) {
-                Some(result) => result,
-                None => return Err(PIE { kind: NegOverflow }),
+        macro_rules! run_checked_loop {
+            ($checked_additive_op:ident, $overflow_err:expr) => {
+                for &c in digits {
+                    // When `radix` is passed in as a literal, rather than doing a slow `imul`
+                    // the compiler can use shifts if `radix` can be expressed as a
+                    // sum of powers of 2 (x*10 can be written as x*8 + x*2).
+                    // When the compiler can't use these optimisations,
+                    // the latency of the multiplication can be hidden by issuing it
+                    // before the result is needed to improve performance on
+                    // modern out-of-order CPU as multiplication here is slower
+                    // than the other instructions, we can get the end result faster
+                    // doing multiplication first and let the CPU spends other cycles
+                    // doing other computation and get multiplication result later.
+                    let mul = result.checked_mul(radix);
+                    let x = (c as char).to_digit(radix).ok_or(PIE { kind: InvalidDigit })?;
+                    result = mul.ok_or_else($overflow_err)?;
+                    result = T::$checked_additive_op(&result, x).ok_or_else($overflow_err)?;
+                }
             };
         }
+        if is_positive {
+            run_checked_loop!(checked_add, || PIE { kind: PosOverflow })
+        } else {
+            run_checked_loop!(checked_sub, || PIE { kind: NegOverflow })
+        };
     }
     Ok(result)
 }
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index cef6a68b4d3..720317b05e0 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -175,7 +175,7 @@
 //! relies on pinning requires unsafe code, but be aware that deciding to make
 //! use of pinning in your type (for example by implementing some operation on
 //! <code>[Pin]<[&]Self></code> or <code>[Pin]<[&mut] Self></code>) has consequences for your
-//! [`Drop`][Drop]implementation as well: if an element of your type could have been pinned,
+//! [`Drop`][Drop] implementation as well: if an element of your type could have been pinned,
 //! you must treat [`Drop`][Drop] as implicitly taking <code>[Pin]<[&mut] Self></code>.
 //!
 //! For example, you could implement [`Drop`][Drop] as follows:
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 2240c297a25..2a4030de00b 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -2331,12 +2331,13 @@ impl<T> [T] {
     /// ```
     ///
     /// If you want to insert an item to a sorted vector, while maintaining
-    /// sort order:
+    /// sort order, consider using [`partition_point`]:
     ///
     /// ```
     /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
     /// let num = 42;
-    /// let idx = s.binary_search(&num).unwrap_or_else(|x| x);
+    /// let idx = s.partition_point(|&x| x < num);
+    /// // The above is equivalent to `let idx = s.binary_search(&num).unwrap_or_else(|x| x);`
     /// s.insert(idx, num);
     /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
     /// ```
@@ -3743,6 +3744,17 @@ impl<T> [T] {
     /// assert!(v[..i].iter().all(|&x| x < 5));
     /// assert!(v[i..].iter().all(|&x| !(x < 5)));
     /// ```
+    ///
+    /// If you want to insert an item to a sorted vector, while maintaining
+    /// sort order:
+    ///
+    /// ```
+    /// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+    /// let num = 42;
+    /// let idx = s.partition_point(|&x| x < num);
+    /// s.insert(idx, num);
+    /// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
+    /// ```
     #[stable(feature = "partition_point", since = "1.52.0")]
     #[must_use]
     pub fn partition_point<P>(&self, mut pred: P) -> usize
diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs
index ef26cbfb640..81b1db4ac6f 100644
--- a/library/core/src/str/converts.rs
+++ b/library/core/src/str/converts.rs
@@ -144,11 +144,7 @@ pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
 ///
 /// # Safety
 ///
-/// This function is unsafe because it does not check that the bytes passed to
-/// it are valid UTF-8. If this constraint is violated, undefined behavior
-/// results, as the rest of Rust assumes that [`&str`]s are valid UTF-8.
-///
-/// [`&str`]: str
+/// The bytes passed in must be valid UTF-8.
 ///
 /// # Examples
 ///
diff --git a/library/core/tests/alloc.rs b/library/core/tests/alloc.rs
index 628ac3a45ff..6762c0319e5 100644
--- a/library/core/tests/alloc.rs
+++ b/library/core/tests/alloc.rs
@@ -17,7 +17,7 @@ fn layout_debug_shows_log2_of_alignment() {
     // `Debug` is not stable, but here's what it does right now
     let layout = Layout::from_size_align(24576, 8192).unwrap();
     let s = format!("{:?}", layout);
-    assert_eq!(s, "Layout { size_: 24576, align_: 8192 (1 << 13) }");
+    assert_eq!(s, "Layout { size: 24576, align: 8192 (1 << 13) }");
 }
 
 // Running this normally doesn't do much, but it's also run in Miri, which
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 09e2e04a1e5..447a6fcf756 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -53,6 +53,7 @@
 #![feature(numfmt)]
 #![feature(step_trait)]
 #![feature(str_internals)]
+#![feature(std_internals)]
 #![feature(test)]
 #![feature(trusted_len)]
 #![feature(try_blocks)]
diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
index 4f773a824ef..49580cdcc48 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -2,7 +2,7 @@ use core::cmp::PartialEq;
 use core::convert::{TryFrom, TryInto};
 use core::fmt::Debug;
 use core::marker::Copy;
-use core::num::{IntErrorKind, ParseIntError, TryFromIntError};
+use core::num::{can_not_overflow, IntErrorKind, ParseIntError, TryFromIntError};
 use core::ops::{Add, Div, Mul, Rem, Sub};
 use core::option::Option;
 use core::option::Option::None;
@@ -121,6 +121,75 @@ fn test_int_from_str_overflow() {
 }
 
 #[test]
+fn test_can_not_overflow() {
+    fn can_overflow<T>(radix: u32, input: &str) -> bool
+    where
+        T: std::convert::TryFrom<i8>,
+    {
+        !can_not_overflow::<T>(radix, T::try_from(-1_i8).is_ok(), input.as_bytes())
+    }
+
+    // Positive tests:
+    assert!(!can_overflow::<i8>(16, "F"));
+    assert!(!can_overflow::<u8>(16, "FF"));
+
+    assert!(!can_overflow::<i8>(10, "9"));
+    assert!(!can_overflow::<u8>(10, "99"));
+
+    // Negative tests:
+
+    // Not currently in std lib (issue: #27728)
+    fn format_radix<T>(mut x: T, radix: T) -> String
+    where
+        T: std::ops::Rem<Output = T>,
+        T: std::ops::Div<Output = T>,
+        T: std::cmp::PartialEq,
+        T: std::default::Default,
+        T: Copy,
+        T: Default,
+        u32: TryFrom<T>,
+    {
+        let mut result = vec![];
+
+        loop {
+            let m = x % radix;
+            x = x / radix;
+            result.push(
+                std::char::from_digit(m.try_into().ok().unwrap(), radix.try_into().ok().unwrap())
+                    .unwrap(),
+            );
+            if x == T::default() {
+                break;
+            }
+        }
+        result.into_iter().rev().collect()
+    }
+
+    macro_rules! check {
+        ($($t:ty)*) => ($(
+        for base in 2..=36 {
+            let num = (<$t>::MAX as u128) + 1;
+
+           // Calcutate the string length for the smallest overflowing number:
+           let max_len_string = format_radix(num, base as u128);
+           // Ensure that that string length is deemed to potentially overflow:
+           assert!(can_overflow::<$t>(base, &max_len_string));
+        }
+        )*)
+    }
+
+    check! { i8 i16 i32 i64 i128 isize usize u8 u16 u32 u64 }
+
+    // Check u128 separately:
+    for base in 2..=36 {
+        let num = u128::MAX as u128;
+        let max_len_string = format_radix(num, base as u128);
+        // base 16 fits perfectly for u128 and won't overflow:
+        assert_eq!(can_overflow::<u128>(base, &max_len_string), base != 16);
+    }
+}
+
+#[test]
 fn test_leading_plus() {
     test_parse::<u8>("+127", Ok(127));
     test_parse::<i64>("+9223372036854775807", Ok(9223372036854775807));
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 807b057234a..e6013c7c051 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -8,7 +8,7 @@ use crate::fmt;
 use crate::fs;
 use crate::marker::PhantomData;
 use crate::mem::forget;
-#[cfg(not(any(target_os = "wasi", target_env = "sgx")))]
+#[cfg(not(any(target_arch = "wasm32", target_env = "sgx")))]
 use crate::sys::cvt;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 
@@ -76,7 +76,7 @@ impl BorrowedFd<'_> {
 impl OwnedFd {
     /// Creates a new `OwnedFd` instance that shares the same underlying file handle
     /// as the existing `OwnedFd` instance.
-    #[cfg(not(target_os = "wasi"))]
+    #[cfg(not(target_arch = "wasm32"))]
     pub fn try_clone(&self) -> crate::io::Result<Self> {
         // We want to atomically duplicate this file descriptor and set the
         // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
@@ -95,7 +95,7 @@ impl OwnedFd {
         Ok(unsafe { Self::from_raw_fd(fd) })
     }
 
-    #[cfg(target_os = "wasi")]
+    #[cfg(target_arch = "wasm32")]
     pub fn try_clone(&self) -> crate::io::Result<Self> {
         Err(crate::io::const_io_error!(
             crate::io::ErrorKind::Unsupported,
diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs
index f9c883dd6bf..47ee88d97fb 100644
--- a/library/std/src/os/fd/raw.rs
+++ b/library/std/src/os/fd/raw.rs
@@ -5,7 +5,7 @@
 use crate::fs;
 use crate::io;
 use crate::os::raw;
-#[cfg(doc)]
+#[cfg(all(doc, not(target_arch = "wasm32")))]
 use crate::os::unix::io::AsFd;
 #[cfg(unix)]
 use crate::os::unix::io::OwnedFd;
diff --git a/library/std/src/sys/unix/futex.rs b/library/std/src/sys/unix/futex.rs
index c61d948fb60..b45d1c0149c 100644
--- a/library/std/src/sys/unix/futex.rs
+++ b/library/std/src/sys/unix/futex.rs
@@ -7,6 +7,11 @@
 use crate::sync::atomic::AtomicI32;
 use crate::time::Duration;
 
+/// Wait for a futex_wake operation to wake us.
+///
+/// Returns directly if the futex doesn't hold the expected value.
+///
+/// Returns false on timeout, and true in all other cases.
 #[cfg(any(target_os = "linux", target_os = "android"))]
 pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) -> bool {
     use super::time::Timespec;
@@ -68,18 +73,23 @@ pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) {
     }
 }
 
+/// Wake up one thread that's blocked on futex_wait on this futex.
+///
+/// Returns true if this actually woke up such a thread,
+/// or false if no thread was waiting on this futex.
 #[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn futex_wake(futex: &AtomicI32) {
+pub fn futex_wake(futex: &AtomicI32) -> bool {
     unsafe {
         libc::syscall(
             libc::SYS_futex,
             futex as *const AtomicI32,
             libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG,
             1,
-        );
+        ) > 0
     }
 }
 
+/// Wake up all threads that are waiting on futex_wait on this futex.
 #[cfg(any(target_os = "linux", target_os = "android"))]
 pub fn futex_wake_all(futex: &AtomicI32) {
     unsafe {
@@ -93,12 +103,10 @@ pub fn futex_wake_all(futex: &AtomicI32) {
 }
 
 #[cfg(target_os = "emscripten")]
-pub fn futex_wake(futex: &AtomicI32) {
+pub fn futex_wake(futex: &AtomicI32) -> bool {
     extern "C" {
         fn emscripten_futex_wake(addr: *const AtomicI32, count: libc::c_int) -> libc::c_int;
     }
 
-    unsafe {
-        emscripten_futex_wake(futex as *const AtomicI32, 1);
-    }
+    unsafe { emscripten_futex_wake(futex as *const AtomicI32, 1) > 0 }
 }
diff --git a/library/std/src/sys/unix/locks/futex_rwlock.rs b/library/std/src/sys/unix/locks/futex_rwlock.rs
new file mode 100644
index 00000000000..aa16da97e4c
--- /dev/null
+++ b/library/std/src/sys/unix/locks/futex_rwlock.rs
@@ -0,0 +1,313 @@
+use crate::sync::atomic::{
+    AtomicI32,
+    Ordering::{Acquire, Relaxed, Release},
+};
+use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all};
+
+pub type MovableRwLock = RwLock;
+
+pub struct RwLock {
+    // The state consists of a 30-bit reader counter, a 'readers waiting' flag, and a 'writers waiting' flag.
+    // Bits 0..30:
+    //   0: Unlocked
+    //   1..=0x3FFF_FFFE: Locked by N readers
+    //   0x3FFF_FFFF: Write locked
+    // Bit 30: Readers are waiting on this futex.
+    // Bit 31: Writers are waiting on the writer_notify futex.
+    state: AtomicI32,
+    // The 'condition variable' to notify writers through.
+    // Incremented on every signal.
+    writer_notify: AtomicI32,
+}
+
+const READ_LOCKED: i32 = 1;
+const MASK: i32 = (1 << 30) - 1;
+const WRITE_LOCKED: i32 = MASK;
+const MAX_READERS: i32 = MASK - 1;
+const READERS_WAITING: i32 = 1 << 30;
+const WRITERS_WAITING: i32 = 1 << 31;
+
+fn is_unlocked(state: i32) -> bool {
+    state & MASK == 0
+}
+
+fn is_write_locked(state: i32) -> bool {
+    state & MASK == WRITE_LOCKED
+}
+
+fn has_readers_waiting(state: i32) -> bool {
+    state & READERS_WAITING != 0
+}
+
+fn has_writers_waiting(state: i32) -> bool {
+    state & WRITERS_WAITING != 0
+}
+
+fn is_read_lockable(state: i32) -> bool {
+    // This also returns false if the counter could overflow if we tried to read lock it.
+    //
+    // We don't allow read-locking if there's readers waiting, even if the lock is unlocked
+    // and there's no writers waiting. The only situation when this happens is after unlocking,
+    // at which point the unlocking thread might be waking up writers, which have priority over readers.
+    // The unlocking thread will clear the readers waiting bit and wake up readers, if necssary.
+    state & MASK < MAX_READERS && !has_readers_waiting(state) && !has_writers_waiting(state)
+}
+
+fn has_reached_max_readers(state: i32) -> bool {
+    state & MASK == MAX_READERS
+}
+
+impl RwLock {
+    #[inline]
+    pub const fn new() -> Self {
+        Self { state: AtomicI32::new(0), writer_notify: AtomicI32::new(0) }
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {}
+
+    #[inline]
+    pub unsafe fn try_read(&self) -> bool {
+        self.state
+            .fetch_update(Acquire, Relaxed, |s| is_read_lockable(s).then(|| s + READ_LOCKED))
+            .is_ok()
+    }
+
+    #[inline]
+    pub unsafe fn read(&self) {
+        let state = self.state.load(Relaxed);
+        if !is_read_lockable(state)
+            || self
+                .state
+                .compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed)
+                .is_err()
+        {
+            self.read_contended();
+        }
+    }
+
+    #[inline]
+    pub unsafe fn read_unlock(&self) {
+        let state = self.state.fetch_sub(READ_LOCKED, Release) - READ_LOCKED;
+
+        // It's impossible for a reader to be waiting on a read-locked RwLock,
+        // except if there is also a writer waiting.
+        debug_assert!(!has_readers_waiting(state) || has_writers_waiting(state));
+
+        // Wake up a writer if we were the last reader and there's a writer waiting.
+        if is_unlocked(state) && has_writers_waiting(state) {
+            self.wake_writer_or_readers(state);
+        }
+    }
+
+    #[cold]
+    fn read_contended(&self) {
+        let mut state = self.spin_read();
+
+        loop {
+            // If we can lock it, lock it.
+            if is_read_lockable(state) {
+                match self.state.compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed)
+                {
+                    Ok(_) => return, // Locked!
+                    Err(s) => {
+                        state = s;
+                        continue;
+                    }
+                }
+            }
+
+            // Check for overflow.
+            if has_reached_max_readers(state) {
+                panic!("too many active read locks on RwLock");
+            }
+
+            // Make sure the readers waiting bit is set before we go to sleep.
+            if !has_readers_waiting(state) {
+                if let Err(s) =
+                    self.state.compare_exchange(state, state | READERS_WAITING, Relaxed, Relaxed)
+                {
+                    state = s;
+                    continue;
+                }
+            }
+
+            // Wait for the state to change.
+            futex_wait(&self.state, state | READERS_WAITING, None);
+
+            // Spin again after waking up.
+            state = self.spin_read();
+        }
+    }
+
+    #[inline]
+    pub unsafe fn try_write(&self) -> bool {
+        self.state
+            .fetch_update(Acquire, Relaxed, |s| is_unlocked(s).then(|| s + WRITE_LOCKED))
+            .is_ok()
+    }
+
+    #[inline]
+    pub unsafe fn write(&self) {
+        if self.state.compare_exchange_weak(0, WRITE_LOCKED, Acquire, Relaxed).is_err() {
+            self.write_contended();
+        }
+    }
+
+    #[inline]
+    pub unsafe fn write_unlock(&self) {
+        let state = self.state.fetch_sub(WRITE_LOCKED, Release) - WRITE_LOCKED;
+
+        debug_assert!(is_unlocked(state));
+
+        if has_writers_waiting(state) || has_readers_waiting(state) {
+            self.wake_writer_or_readers(state);
+        }
+    }
+
+    #[cold]
+    fn write_contended(&self) {
+        let mut state = self.spin_write();
+
+        let mut other_writers_waiting = 0;
+
+        loop {
+            // If it's unlocked, we try to lock it.
+            if is_unlocked(state) {
+                match self.state.compare_exchange_weak(
+                    state,
+                    state | WRITE_LOCKED | other_writers_waiting,
+                    Acquire,
+                    Relaxed,
+                ) {
+                    Ok(_) => return, // Locked!
+                    Err(s) => {
+                        state = s;
+                        continue;
+                    }
+                }
+            }
+
+            // Set the waiting bit indicating that we're waiting on it.
+            if !has_writers_waiting(state) {
+                if let Err(s) =
+                    self.state.compare_exchange(state, state | WRITERS_WAITING, Relaxed, Relaxed)
+                {
+                    state = s;
+                    continue;
+                }
+            }
+
+            // Other writers might be waiting now too, so we should make sure
+            // we keep that bit on once we manage lock it.
+            other_writers_waiting = WRITERS_WAITING;
+
+            // Examine the notification counter before we check if `state` has changed,
+            // to make sure we don't miss any notifications.
+            let seq = self.writer_notify.load(Acquire);
+
+            // Don't go to sleep if the lock has become available,
+            // or if the writers waiting bit is no longer set.
+            let s = self.state.load(Relaxed);
+            if is_unlocked(state) || !has_writers_waiting(s) {
+                state = s;
+                continue;
+            }
+
+            // Wait for the state to change.
+            futex_wait(&self.writer_notify, seq, None);
+
+            // Spin again after waking up.
+            state = self.spin_write();
+        }
+    }
+
+    /// Wake up waiting threads after unlocking.
+    ///
+    /// If both are waiting, this will wake up only one writer, but will fall
+    /// back to waking up readers if there was no writer to wake up.
+    #[cold]
+    fn wake_writer_or_readers(&self, mut state: i32) {
+        assert!(is_unlocked(state));
+
+        // The readers waiting bit might be turned on at any point now,
+        // since readers will block when there's anything waiting.
+        // Writers will just lock the lock though, regardless of the waiting bits,
+        // so we don't have to worry about the writer waiting bit.
+        //
+        // If the lock gets locked in the meantime, we don't have to do
+        // anything, because then the thread that locked the lock will take
+        // care of waking up waiters when it unlocks.
+
+        // If only writers are waiting, wake one of them up.
+        if state == WRITERS_WAITING {
+            match self.state.compare_exchange(state, 0, Relaxed, Relaxed) {
+                Ok(_) => {
+                    self.wake_writer();
+                    return;
+                }
+                Err(s) => {
+                    // Maybe some readers are now waiting too. So, continue to the next `if`.
+                    state = s;
+                }
+            }
+        }
+
+        // If both writers and readers are waiting, leave the readers waiting
+        // and only wake up one writer.
+        if state == READERS_WAITING + WRITERS_WAITING {
+            if self.state.compare_exchange(state, READERS_WAITING, Relaxed, Relaxed).is_err() {
+                // The lock got locked. Not our problem anymore.
+                return;
+            }
+            if self.wake_writer() {
+                return;
+            }
+            // No writers were actually blocked on futex_wait, so we continue
+            // to wake up readers instead, since we can't be sure if we notified a writer.
+            state = READERS_WAITING;
+        }
+
+        // If readers are waiting, wake them all up.
+        if state == READERS_WAITING {
+            if self.state.compare_exchange(state, 0, Relaxed, Relaxed).is_ok() {
+                futex_wake_all(&self.state);
+            }
+        }
+    }
+
+    /// This wakes one writer and returns true if we woke up a writer that was
+    /// blocked on futex_wait.
+    ///
+    /// If this returns false, it might still be the case that we notified a
+    /// writer that was about to go to sleep.
+    fn wake_writer(&self) -> bool {
+        self.writer_notify.fetch_add(1, Release);
+        futex_wake(&self.writer_notify)
+    }
+
+    /// Spin for a while, but stop directly at the given condition.
+    fn spin_until(&self, f: impl Fn(i32) -> bool) -> i32 {
+        let mut spin = 100; // Chosen by fair dice roll.
+        loop {
+            let state = self.state.load(Relaxed);
+            if f(state) || spin == 0 {
+                return state;
+            }
+            crate::hint::spin_loop();
+            spin -= 1;
+        }
+    }
+
+    fn spin_write(&self) -> i32 {
+        // Stop spinning when it's unlocked or when there's waiting writers, to keep things somewhat fair.
+        self.spin_until(|state| is_unlocked(state) || has_writers_waiting(state))
+    }
+
+    fn spin_read(&self) -> i32 {
+        // Stop spinning when it's unlocked or read locked, or when there's waiting threads.
+        self.spin_until(|state| {
+            !is_write_locked(state) || has_readers_waiting(state) || has_writers_waiting(state)
+        })
+    }
+}
diff --git a/library/std/src/sys/unix/locks/mod.rs b/library/std/src/sys/unix/locks/mod.rs
index 2b8dd168068..85afc939d2e 100644
--- a/library/std/src/sys/unix/locks/mod.rs
+++ b/library/std/src/sys/unix/locks/mod.rs
@@ -4,13 +4,13 @@ cfg_if::cfg_if! {
         target_os = "android",
     ))] {
         mod futex;
+        mod futex_rwlock;
         #[allow(dead_code)]
         mod pthread_mutex; // Only used for PthreadMutexAttr, needed by pthread_remutex.
         mod pthread_remutex; // FIXME: Implement this using a futex
-        mod pthread_rwlock; // FIXME: Implement this using a futex
         pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
         pub use pthread_remutex::ReentrantMutex;
-        pub use pthread_rwlock::{RwLock, MovableRwLock};
+        pub use futex_rwlock::{RwLock, MovableRwLock};
     } else {
         mod pthread_mutex;
         mod pthread_remutex;
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 0b6bdf47419..9af0657caff 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -122,6 +122,7 @@ def _download(path, url, probably_big, verbose, exception, help_on_error=None):
             option = "-s"
         require(["curl", "--version"])
         run(["curl", option,
+             "-L", # Follow redirect.
              "-y", "30", "-Y", "10",    # timeout if speed is < 10 bytes/sec for > 30 seconds
              "--connect-timeout", "30",  # timeout if cannot connect within 30 seconds
              "--retry", "3", "-Sf", "-o", path, url],
@@ -1097,8 +1098,19 @@ class RustBuild(object):
 
     def update_submodules(self):
         """Update submodules"""
-        if (not os.path.exists(os.path.join(self.rust_root, ".git"))) or \
-                self.get_toml('submodules') == "false":
+        has_git = os.path.exists(os.path.join(self.rust_root, ".git"))
+        # This just arbitrarily checks for cargo, but any workspace member in
+        # a submodule would work.
+        has_submodules = os.path.exists(os.path.join(self.rust_root, "src/tools/cargo/Cargo.toml"))
+        if not has_git and not has_submodules:
+            print("This is not a git repository, and the requisite git submodules were not found.")
+            print("If you downloaded the source from https://github.com/rust-lang/rust/releases,")
+            print("those sources will not work. Instead, consider downloading from the source")
+            print("releases linked at")
+            print("https://forge.rust-lang.org/infra/other-installation-methods.html#source-code")
+            print("or clone the repository at https://github.com/rust-lang/rust/.")
+            raise SystemExit(1)
+        if not has_git or self.get_toml('submodules') == "false":
             return
 
         default_encoding = sys.getdefaultencoding()
@@ -1161,9 +1173,9 @@ class RustBuild(object):
         """Check that vendoring is configured properly"""
         vendor_dir = os.path.join(self.rust_root, 'vendor')
         if 'SUDO_USER' in os.environ and not self.use_vendored_sources:
-            if os.environ.get('USER') != os.environ['SUDO_USER']:
+            if os.getuid() == 0:
                 self.use_vendored_sources = True
-                print('info: looks like you are running this command under `sudo`')
+                print('info: looks like you\'re trying to run this command as root')
                 print('      and so in order to preserve your $HOME this will now')
                 print('      use vendored sources by default.')
                 if not os.path.exists(vendor_dir):
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 8c06a007013..0276d15a5b4 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -621,9 +621,9 @@ impl<'a> Builder<'a> {
 
     pub fn get_help(build: &Build, subcommand: &str) -> Option<String> {
         let kind = match subcommand {
-            "build" => Kind::Build,
-            "doc" => Kind::Doc,
-            "test" => Kind::Test,
+            "build" | "b" => Kind::Build,
+            "doc" | "d" => Kind::Doc,
+            "test" | "t" => Kind::Test,
             "bench" => Kind::Bench,
             "dist" => Kind::Dist,
             "install" => Kind::Install,
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 28e7f1fdca7..432a6c34ed5 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -243,12 +243,7 @@ impl Step for CodegenBackend {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.paths(&[
-            "compiler/rustc_codegen_cranelift",
-            "rustc_codegen_cranelift",
-            "compiler/rustc_codegen_gcc",
-            "rustc_codegen_gcc",
-        ])
+        run.paths(&["compiler/rustc_codegen_cranelift", "compiler/rustc_codegen_gcc"])
     }
 
     fn make_run(run: RunConfig<'_>) {
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index afc333b5048..45991381dc0 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -795,7 +795,7 @@ impl Step for CodegenBackend {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("compiler/rustc_codegen_cranelift")
+        run.paths(&["compiler/rustc_codegen_cranelift", "compiler/rustc_codegen_gcc"])
     }
 
     fn make_run(run: RunConfig<'_>) {
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index e4937d7bbcc..7b496e6c669 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -865,8 +865,8 @@ impl Build {
                 }
             }
         } else {
-            let base = self.llvm_out(self.config.build).join("build");
-            let base = if !self.ninja() && self.config.build.contains("msvc") {
+            let base = self.llvm_out(target).join("build");
+            let base = if !self.ninja() && target.contains("msvc") {
                 if self.config.llvm_optimize {
                     if self.config.llvm_release_debuginfo {
                         base.join("RelWithDebInfo")
diff --git a/src/ci/pgo.sh b/src/ci/pgo.sh
index 689e6a11d61..691d1282cf4 100755
--- a/src/ci/pgo.sh
+++ b/src/ci/pgo.sh
@@ -47,12 +47,6 @@ python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \
     --stage 2 library/std \
     --llvm-profile-generate
 
-# Profile libcore compilation in opt-level=0 and opt-level=3
-RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc \
-    --edition=2021 --crate-type=lib ../library/core/src/lib.rs
-RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc \
-    --edition=2021 --crate-type=lib -Copt-level=3 ../library/core/src/lib.rs
-
 # Compile rustc perf
 cp -r /tmp/rustc-perf ./
 chown -R $(whoami): ./rustc-perf
diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md
index 941c65922d8..e7bf8d9a36f 100644
--- a/src/doc/rustc/src/linker-plugin-lto.md
+++ b/src/doc/rustc/src/linker-plugin-lto.md
@@ -136,7 +136,7 @@ able to get around this problem by setting `-Clinker=lld-link` in RUSTFLAGS
 ```sh
 rustup toolchain install --profile minimal nightly
 MINOR_VERSION=$(rustc +nightly --version | cut -d . -f 2)
-LOWER_BOUND=44
+LOWER_BOUND=61
 
 llvm_version() {
     toolchain="$1"
@@ -179,5 +179,19 @@ The following table shows known good combinations of toolchain versions.
 | Rust 1.44    |    Clang 9    |
 | Rust 1.45    |    Clang 10   |
 | Rust 1.46    |    Clang 10   |
+| Rust 1.47    |    Clang 11   |
+| Rust 1.48    |    Clang 11   |
+| Rust 1.49    |    Clang 11   |
+| Rust 1.50    |    Clang 11   |
+| Rust 1.51    |    Clang 11   |
+| Rust 1.52    |    Clang 12   |
+| Rust 1.53    |    Clang 12   |
+| Rust 1.54    |    Clang 12   |
+| Rust 1.55    |    Clang 12   |
+| Rust 1.56    |    Clang 13   |
+| Rust 1.57    |    Clang 13   |
+| Rust 1.58    |    Clang 13   |
+| Rust 1.59    |    Clang 13   |
+| Rust 1.60    |    Clang 14   |
 
 Note that the compatibility policy for this feature might change in the future.
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 32def67ed65..b3c4a52c414 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -31,18 +31,20 @@ All tier 1 targets with host tools support the full standard library.
 target | notes
 -------|-------
 `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.2, glibc 2.17+) [^missing-stack-probes]
-`i686-pc-windows-gnu` | 32-bit MinGW (Windows 7+)
-`i686-pc-windows-msvc` | 32-bit MSVC (Windows 7+)
+`i686-pc-windows-gnu` | 32-bit MinGW (Windows 7+) [^windows-support]
+`i686-pc-windows-msvc` | 32-bit MSVC (Windows 7+) [^windows-support]
 `i686-unknown-linux-gnu` | 32-bit Linux (kernel 2.6.32+, glibc 2.11+)
 `x86_64-apple-darwin` | 64-bit macOS (10.7+, Lion+)
-`x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 7+)
-`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 7+)
+`x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 7+) [^windows-support]
+`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 7+) [^windows-support]
 `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 2.6.32+, glibc 2.11+)
 
 [^missing-stack-probes]: Stack probes support is missing on
   `aarch64-unknown-linux-gnu`, but it's planned to be implemented in the near
   future. The implementation is tracked on [issue #77071][77071].
 
+[^windows-support]: Only Windows 10 currently undergoes automated testing. Earlier versions of Windows rely on testing and support from the community.
+
 [77071]: https://github.com/rust-lang/rust/issues/77071
 
 ## Tier 1
diff --git a/src/etc/pre-push.sh b/src/etc/pre-push.sh
index a78725f2ab0..5f5b48bc1c0 100755
--- a/src/etc/pre-push.sh
+++ b/src/etc/pre-push.sh
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 #
-# Call `tidy --bless` before each commit
+# Call `tidy --bless` before git push
 # Copy this script to .git/hooks to activate,
 # and remove it from .git/hooks to deactivate.
 #
@@ -14,6 +14,8 @@ COMMAND="$ROOT_DIR/x.py test tidy --bless"
 
 if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
   COMMAND="python $COMMAND"
+elif ! command -v python &> /dev/null; then
+  COMMAND="python3 $COMMAND"
 fi
 
 echo "Running pre-push script '$COMMAND'"
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index e6ef3c26e29..85a3e05e8b2 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -302,23 +302,13 @@ impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
 
 impl<'a> Clean<Option<WherePredicate>> for ty::PolyTraitPredicate<'a> {
     fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
-        // `T: ~const Drop` is not equivalent to `T: Drop`, and we don't currently document `~const` bounds
-        // because of its experimental status, so just don't show these.
         // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
         if self.skip_binder().constness == ty::BoundConstness::ConstIfConst
-            && [cx.tcx.lang_items().drop_trait(), cx.tcx.lang_items().destruct_trait()]
-                .iter()
-                .any(|tr| *tr == Some(self.skip_binder().def_id()))
+            && Some(self.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait()
         {
             return None;
         }
 
-        #[cfg(bootstrap)]
-        {
-            // FIXME: remove `lang_items().drop_trait()` from above logic,
-            // as well as the comment about `~const Drop` because it was renamed to `Destruct`.
-        }
-
         let poly_trait_ref = self.map_bound(|pred| pred.trait_ref);
         Some(WherePredicate::BoundPredicate {
             ty: poly_trait_ref.skip_binder().self_ty().clean(cx),
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 50ae22b99cd..eabe0803b49 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -1069,13 +1069,7 @@ impl Tester for Collector {
                             }
                         }
                         TestFailure::ExecutionFailure(out) => {
-                            let reason = if let Some(code) = out.status.code() {
-                                format!("exit code {code}")
-                            } else {
-                                String::from("terminated by signal")
-                            };
-
-                            eprintln!("Test executable failed ({reason}).");
+                            eprintln!("Test executable failed ({reason}).", reason = out.status);
 
                             // FIXME(#12309): An unfortunate side-effect of capturing the test
                             // executable's output is that the relative ordering between the test's
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 3a3d61b1e67..943c521485b 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -251,7 +251,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
             }
         }
         let lines = origtext.lines().filter_map(|l| map_line(l).for_html());
-        let text = lines.collect::<Vec<Cow<'_, str>>>().join("\n");
+        let text = lines.intersperse("\n".into()).collect::<String>();
 
         let parse_result = match kind {
             CodeBlockKind::Fenced(ref lang) => {
@@ -291,15 +291,13 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
             let test = origtext
                 .lines()
                 .map(|l| map_line(l).for_code())
-                .collect::<Vec<Cow<'_, str>>>()
-                .join("\n");
+                .intersperse("\n".into())
+                .collect::<String>();
             let krate = krate.as_ref().map(|s| &**s);
             let (test, _, _) =
                 doctest::make_test(&test, krate, false, &Default::default(), edition, None);
             let channel = if test.contains("#![feature(") { "&amp;version=nightly" } else { "" };
 
-            let edition_string = format!("&amp;edition={}", edition);
-
             // These characters don't need to be escaped in a URI.
             // FIXME: use a library function for percent encoding.
             fn dont_escape(c: u8) -> bool {
@@ -325,8 +323,8 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
                 }
             }
             Some(format!(
-                r#"<a class="test-arrow" target="_blank" href="{}?code={}{}{}">Run</a>"#,
-                url, test_escaped, channel, edition_string
+                r#"<a class="test-arrow" target="_blank" href="{}?code={}{}&amp;edition={}">Run</a>"#,
+                url, test_escaped, channel, edition,
             ))
         });
 
diff --git a/src/librustdoc/theme.rs b/src/librustdoc/theme.rs
index 1e9a65e1d2f..7c19865b6d7 100644
--- a/src/librustdoc/theme.rs
+++ b/src/librustdoc/theme.rs
@@ -173,15 +173,17 @@ fn build_rule(v: &[u8], positions: &[usize]) -> String {
             .map(|x| ::std::str::from_utf8(&v[x[0]..x[1]]).unwrap_or(""))
             .collect::<String>()
             .trim()
-            .replace('\n', " ")
-            .replace('/', "")
-            .replace('\t', " ")
-            .replace('{', "")
-            .replace('}', "")
+            .chars()
+            .filter_map(|c| match c {
+                '\n' | '\t' => Some(' '),
+                '/' | '{' | '}' => None,
+                c => Some(c),
+            })
+            .collect::<String>()
             .split(' ')
             .filter(|s| !s.is_empty())
-            .collect::<Vec<&str>>()
-            .join(" "),
+            .intersperse(" ")
+            .collect::<String>(),
     )
     .unwrap_or_else(|_| String::new())
 }
diff --git a/src/test/codegen/asm-may_unwind.rs b/src/test/codegen/asm-may_unwind.rs
index 3b34d79c3a9..bf4202764a7 100644
--- a/src/test/codegen/asm-may_unwind.rs
+++ b/src/test/codegen/asm-may_unwind.rs
@@ -18,10 +18,23 @@ impl Drop for Foo {
     }
 }
 
-// CHECK-LABEL: @may_unwind
+// CHECK-LABEL: @asm_may_unwind
 #[no_mangle]
-pub unsafe fn may_unwind() {
+pub unsafe fn asm_may_unwind() {
     let _m = Foo;
     // CHECK: invoke void asm sideeffect alignstack inteldialect unwind ""
     asm!("", options(may_unwind));
 }
+
+// CHECK-LABEL: @asm_with_result_may_unwind
+#[no_mangle]
+pub unsafe fn asm_with_result_may_unwind() -> u64 {
+    let _m = Foo;
+    let res: u64;
+    // CHECK: [[RES:%[0-9]+]] = invoke i64 asm sideeffect alignstack inteldialect unwind
+    // CHECK-NEXT: to label %[[NORMALBB:[a-b0-9]+]]
+    asm!("mov {}, 1", out(reg) res, options(may_unwind));
+    // CHECK: [[NORMALBB]]:
+    // CHECK: ret i64 [[RES:%[0-9]+]]
+    res
+}
diff --git a/src/test/codegen/try_identity.rs b/src/test/codegen/try_identity.rs
index 3ff77163b9f..92be90014ff 100644
--- a/src/test/codegen/try_identity.rs
+++ b/src/test/codegen/try_identity.rs
@@ -14,7 +14,7 @@ type R = Result<u64, i32>;
 #[no_mangle]
 pub fn try_identity(x: R) -> R {
 // CHECK: start:
-// CHECK-NOT: br {{.*}}
+// FIXME(JakobDegen): Broken by deaggregation change CHECK-NOT\: br {{.*}}
 // CHECK ret void
     let y = match into_result(x) {
         Err(e) => return from_error(From::from(e)),
diff --git a/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff b/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff
index 1969d5e0404..884275430c8 100644
--- a/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff
+++ b/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff
@@ -17,6 +17,7 @@
       }
   
       bb2: {
+          Deinit(_0);                      // scope 0 at $DIR/76803_regression.rs:12:20: 12:27
           discriminant(_0) = 1;            // scope 0 at $DIR/76803_regression.rs:12:20: 12:27
           goto -> bb3;                     // scope 0 at $DIR/76803_regression.rs:12:20: 12:27
       }
diff --git a/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
index 62e5da4902c..678e965cd67 100644
--- a/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
+++ b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
@@ -63,6 +63,7 @@
       }
   
       bb3: {
+          Deinit(_0);                      // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
           (_0.0: T) = move _5;             // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
           (_0.1: u64) = move _8;           // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
           (_0.2: [f32; 3]) = move _11;     // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
diff --git a/src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
index 7ed25c6c09e..7dd420e41ce 100644
--- a/src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
+++ b/src/test/mir-opt/const_debuginfo.main.ConstDebugInfo.diff
@@ -79,13 +79,16 @@
                                            // + span: $DIR/const_debuginfo.rs:14:13: 14:28
                                            // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [104, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [8191], len: Size { raw: 13 } }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 13 }) }
           StorageLive(_10);                // scope 5 at $DIR/const_debuginfo.rs:16:9: 16:10
+          Deinit(_10);                     // scope 5 at $DIR/const_debuginfo.rs:16:13: 16:34
           (_10.0: bool) = const true;      // scope 5 at $DIR/const_debuginfo.rs:16:13: 16:34
           (_10.1: bool) = const false;     // scope 5 at $DIR/const_debuginfo.rs:16:13: 16:34
           (_10.2: u32) = const 123_u32;    // scope 5 at $DIR/const_debuginfo.rs:16:13: 16:34
           StorageLive(_11);                // scope 6 at $DIR/const_debuginfo.rs:18:9: 18:10
+          Deinit(_11);                     // scope 6 at $DIR/const_debuginfo.rs:18:13: 18:24
           ((_11 as Some).0: u16) = const 99_u16; // scope 6 at $DIR/const_debuginfo.rs:18:13: 18:24
           discriminant(_11) = 1;           // scope 6 at $DIR/const_debuginfo.rs:18:13: 18:24
           StorageLive(_12);                // scope 7 at $DIR/const_debuginfo.rs:20:9: 20:10
+          Deinit(_12);                     // scope 7 at $DIR/const_debuginfo.rs:20:13: 20:35
           (_12.0: u32) = const 32_u32;     // scope 7 at $DIR/const_debuginfo.rs:20:13: 20:35
           (_12.1: u32) = const 32_u32;     // scope 7 at $DIR/const_debuginfo.rs:20:13: 20:35
           StorageLive(_13);                // scope 8 at $DIR/const_debuginfo.rs:21:9: 21:10
diff --git a/src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff b/src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff
index aee7e22a60f..62a681e1c12 100644
--- a/src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff
+++ b/src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff
@@ -17,6 +17,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/const_goto_storage.rs:3:9: 3:12
 -         StorageLive(_2);                 // scope 0 at $DIR/const_goto_storage.rs:3:21: 3:23
+-         nop;                             // scope 0 at $DIR/const_goto_storage.rs:3:21: 3:23
 -         StorageLive(_3);                 // scope 0 at $DIR/const_goto_storage.rs:4:15: 8:10
 -         StorageLive(_4);                 // scope 0 at $DIR/const_goto_storage.rs:4:18: 4:76
 -         StorageLive(_5);                 // scope 0 at $DIR/const_goto_storage.rs:4:21: 4:52
diff --git a/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff b/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff
index c3b2e535f0e..821075047cb 100644
--- a/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/aggregate.main.ConstProp.diff
@@ -14,6 +14,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/aggregate.rs:5:9: 5:10
           StorageLive(_2);                 // scope 0 at $DIR/aggregate.rs:5:13: 5:24
           StorageLive(_3);                 // scope 0 at $DIR/aggregate.rs:5:13: 5:22
+          Deinit(_3);                      // scope 0 at $DIR/aggregate.rs:5:13: 5:22
           (_3.0: i32) = const 0_i32;       // scope 0 at $DIR/aggregate.rs:5:13: 5:22
           (_3.1: i32) = const 1_i32;       // scope 0 at $DIR/aggregate.rs:5:13: 5:22
           (_3.2: i32) = const 2_i32;       // scope 0 at $DIR/aggregate.rs:5:13: 5:22
diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff
index de23e5446a0..445732f7022 100644
--- a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff
+++ b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff
@@ -15,6 +15,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/discriminant.rs:11:9: 11:10
           StorageLive(_2);                 // scope 0 at $DIR/discriminant.rs:11:13: 11:64
           StorageLive(_3);                 // scope 0 at $DIR/discriminant.rs:11:34: 11:44
+          Deinit(_3);                      // scope 0 at $DIR/discriminant.rs:11:34: 11:44
           ((_3 as Some).0: bool) = const true; // scope 0 at $DIR/discriminant.rs:11:34: 11:44
           discriminant(_3) = 1;            // scope 0 at $DIR/discriminant.rs:11:34: 11:44
 -         _4 = discriminant(_3);           // scope 0 at $DIR/discriminant.rs:11:21: 11:31
diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff
index de23e5446a0..445732f7022 100644
--- a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff
+++ b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff
@@ -15,6 +15,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/discriminant.rs:11:9: 11:10
           StorageLive(_2);                 // scope 0 at $DIR/discriminant.rs:11:13: 11:64
           StorageLive(_3);                 // scope 0 at $DIR/discriminant.rs:11:34: 11:44
+          Deinit(_3);                      // scope 0 at $DIR/discriminant.rs:11:34: 11:44
           ((_3 as Some).0: bool) = const true; // scope 0 at $DIR/discriminant.rs:11:34: 11:44
           discriminant(_3) = 1;            // scope 0 at $DIR/discriminant.rs:11:34: 11:44
 -         _4 = discriminant(_3);           // scope 0 at $DIR/discriminant.rs:11:21: 11:31
diff --git a/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff b/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
index cf6d8a52a76..c60cf1e481d 100644
--- a/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
@@ -34,6 +34,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/invalid_constant.rs:21:9: 21:22
           StorageLive(_2);                 // scope 2 at $DIR/invalid_constant.rs:21:34: 21:63
+          Deinit(_2);                      // scope 2 at $DIR/invalid_constant.rs:21:34: 21:63
           (_2.0: u32) = const 1114113_u32; // scope 2 at $DIR/invalid_constant.rs:21:34: 21:63
 -         _1 = (_2.1: char);               // scope 2 at $DIR/invalid_constant.rs:21:34: 21:67
 +         _1 = const {transmute(0x00110001): char}; // scope 2 at $DIR/invalid_constant.rs:21:34: 21:67
@@ -41,6 +42,7 @@
           StorageLive(_3);                 // scope 1 at $DIR/invalid_constant.rs:28:9: 28:21
           StorageLive(_4);                 // scope 1 at $DIR/invalid_constant.rs:28:25: 28:59
           StorageLive(_5);                 // scope 4 at $DIR/invalid_constant.rs:28:34: 28:55
+          Deinit(_5);                      // scope 4 at $DIR/invalid_constant.rs:28:34: 28:55
           (_5.0: u32) = const 4_u32;       // scope 4 at $DIR/invalid_constant.rs:28:34: 28:55
 -         _4 = (_5.1: E);                  // scope 4 at $DIR/invalid_constant.rs:28:34: 28:57
 -         _3 = [move _4];                  // scope 1 at $DIR/invalid_constant.rs:28:24: 28:60
@@ -57,6 +59,7 @@
           StorageLive(_6);                 // scope 3 at $DIR/invalid_constant.rs:35:9: 35:31
           StorageLive(_7);                 // scope 3 at $DIR/invalid_constant.rs:35:35: 35:73
           StorageLive(_8);                 // scope 6 at $DIR/invalid_constant.rs:35:44: 35:65
+          Deinit(_8);                      // scope 6 at $DIR/invalid_constant.rs:35:44: 35:65
           (_8.0: u32) = const 0_u32;       // scope 6 at $DIR/invalid_constant.rs:35:44: 35:65
           nop;                             // scope 6 at $DIR/invalid_constant.rs:35:44: 35:71
           nop;                             // scope 3 at $DIR/invalid_constant.rs:35:34: 35:74
diff --git a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff
index c5af2801b47..e874adebbe0 100644
--- a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff
@@ -11,6 +11,8 @@
           StorageLive(_1);                 // scope 0 at $DIR/issue-66971.rs:16:5: 16:23
           StorageLive(_2);                 // scope 0 at $DIR/issue-66971.rs:16:12: 16:22
           StorageLive(_3);                 // scope 0 at $DIR/issue-66971.rs:16:13: 16:15
+          nop;                             // scope 0 at $DIR/issue-66971.rs:16:13: 16:15
+          Deinit(_2);                      // scope 0 at $DIR/issue-66971.rs:16:12: 16:22
           nop;                             // scope 0 at $DIR/issue-66971.rs:16:12: 16:22
           (_2.1: u8) = const 0_u8;         // scope 0 at $DIR/issue-66971.rs:16:12: 16:22
           (_2.2: u8) = const 0_u8;         // scope 0 at $DIR/issue-66971.rs:16:12: 16:22
diff --git a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff
index 2d3289f7ce5..69d31b681b4 100644
--- a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff
@@ -11,8 +11,10 @@
           StorageLive(_1);                 // scope 0 at $DIR/issue-67019.rs:11:5: 11:20
           StorageLive(_2);                 // scope 0 at $DIR/issue-67019.rs:11:10: 11:19
           StorageLive(_3);                 // scope 0 at $DIR/issue-67019.rs:11:11: 11:17
+          Deinit(_3);                      // scope 0 at $DIR/issue-67019.rs:11:11: 11:17
           (_3.0: u8) = const 1_u8;         // scope 0 at $DIR/issue-67019.rs:11:11: 11:17
           (_3.1: u8) = const 2_u8;         // scope 0 at $DIR/issue-67019.rs:11:11: 11:17
+          Deinit(_2);                      // scope 0 at $DIR/issue-67019.rs:11:10: 11:19
 -         (_2.0: (u8, u8)) = move _3;      // scope 0 at $DIR/issue-67019.rs:11:10: 11:19
 +         (_2.0: (u8, u8)) = const (1_u8, 2_u8); // scope 0 at $DIR/issue-67019.rs:11:10: 11:19
           StorageDead(_3);                 // scope 0 at $DIR/issue-67019.rs:11:18: 11:19
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff
index a044d1dcfe1..b1deebe40fa 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff
@@ -14,6 +14,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_aggregate.rs:5:9: 5:14
+          Deinit(_1);                      // scope 0 at $DIR/mutable_variable_aggregate.rs:5:17: 5:25
           (_1.0: i32) = const 42_i32;      // scope 0 at $DIR/mutable_variable_aggregate.rs:5:17: 5:25
           (_1.1: i32) = const 43_i32;      // scope 0 at $DIR/mutable_variable_aggregate.rs:5:17: 5:25
           (_1.1: i32) = const 99_i32;      // scope 1 at $DIR/mutable_variable_aggregate.rs:6:5: 6:13
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff
index 32e425d9b1f..07208ad0d2b 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff
@@ -18,6 +18,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:9: 5:14
+          Deinit(_1);                      // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
           (_1.0: i32) = const 42_i32;      // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
           (_1.1: i32) = const 43_i32;      // scope 0 at $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
           StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:9: 6:10
diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
index 49854f7fba1..247d8f32432 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
@@ -31,6 +31,7 @@
   
       bb1: {
           StorageLive(_2);                 // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:9: 6:14
+          Deinit(_2);                      // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:29: 6:35
           (_2.0: i32) = const 1_i32;       // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:29: 6:35
           (_2.1: i32) = const 2_i32;       // scope 1 at $DIR/mutable_variable_unprop_assign.rs:6:29: 6:35
           StorageLive(_3);                 // scope 2 at $DIR/mutable_variable_unprop_assign.rs:7:11: 7:12
diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff
index 4c3f66cd090..72a613b26b6 100644
--- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff
+++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff
@@ -52,6 +52,7 @@
           StorageDead(_4);                 // scope 1 at $DIR/optimizes_into_variable.rs:13:34: 13:35
           StorageLive(_8);                 // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10
           StorageLive(_9);                 // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
+          Deinit(_9);                      // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
           (_9.0: u32) = const 12_u32;      // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
           (_9.1: u32) = const 42_u32;      // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
 -         _8 = (_9.1: u32);                // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff
index 4c3f66cd090..72a613b26b6 100644
--- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff
+++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff
@@ -52,6 +52,7 @@
           StorageDead(_4);                 // scope 1 at $DIR/optimizes_into_variable.rs:13:34: 13:35
           StorageLive(_8);                 // scope 2 at $DIR/optimizes_into_variable.rs:14:9: 14:10
           StorageLive(_9);                 // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
+          Deinit(_9);                      // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
           (_9.0: u32) = const 12_u32;      // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
           (_9.1: u32) = const 42_u32;      // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:36
 -         _8 = (_9.1: u32);                // scope 2 at $DIR/optimizes_into_variable.rs:14:13: 14:38
diff --git a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
index 15253a364e9..2bcd10f160b 100644
--- a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
@@ -12,6 +12,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/tuple_literal_propagation.rs:3:9: 3:10
+          Deinit(_1);                      // scope 0 at $DIR/tuple_literal_propagation.rs:3:13: 3:19
           (_1.0: u32) = const 1_u32;       // scope 0 at $DIR/tuple_literal_propagation.rs:3:13: 3:19
           (_1.1: u32) = const 2_u32;       // scope 0 at $DIR/tuple_literal_propagation.rs:3:13: 3:19
           StorageLive(_2);                 // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15
diff --git a/src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff b/src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff
index 0864eaba719..dcc4368694c 100644
--- a/src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff
+++ b/src/test/mir-opt/const_prop_miscompile.bar.ConstProp.diff
@@ -19,6 +19,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:12:9: 12:14
+          Deinit(_1);                      // scope 0 at $DIR/const_prop_miscompile.rs:12:17: 12:21
           (_1.0: i32) = const 1_i32;       // scope 0 at $DIR/const_prop_miscompile.rs:12:17: 12:21
           StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:13:5: 15:6
           StorageLive(_3);                 // scope 2 at $DIR/const_prop_miscompile.rs:14:10: 14:22
diff --git a/src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff b/src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff
index f7375cb6113..08730da2f3d 100644
--- a/src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff
+++ b/src/test/mir-opt/const_prop_miscompile.foo.ConstProp.diff
@@ -16,6 +16,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:5:9: 5:14
+          Deinit(_1);                      // scope 0 at $DIR/const_prop_miscompile.rs:5:17: 5:21
           (_1.0: i32) = const 1_i32;       // scope 0 at $DIR/const_prop_miscompile.rs:5:17: 5:21
           StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:6:6: 6:14
           _2 = &mut (_1.0: i32);           // scope 1 at $DIR/const_prop_miscompile.rs:6:6: 6:14
diff --git a/src/test/mir-opt/deaggregator_test.bar.Deaggregator.diff b/src/test/mir-opt/deaggregator_test.bar.Deaggregator.diff
index d3c7136c647..69de05b309f 100644
--- a/src/test/mir-opt/deaggregator_test.bar.Deaggregator.diff
+++ b/src/test/mir-opt/deaggregator_test.bar.Deaggregator.diff
@@ -10,6 +10,7 @@
           StorageLive(_2);                 // scope 0 at $DIR/deaggregator_test.rs:9:14: 9:15
           _2 = _1;                         // scope 0 at $DIR/deaggregator_test.rs:9:14: 9:15
 -         _0 = Baz { x: move _2, y: const 0f32, z: const false }; // scope 0 at $DIR/deaggregator_test.rs:9:5: 9:35
++         Deinit(_0);                      // scope 0 at $DIR/deaggregator_test.rs:9:5: 9:35
 +         (_0.0: usize) = move _2;         // scope 0 at $DIR/deaggregator_test.rs:9:5: 9:35
 +         (_0.1: f32) = const 0f32;        // scope 0 at $DIR/deaggregator_test.rs:9:5: 9:35
 +         (_0.2: bool) = const false;      // scope 0 at $DIR/deaggregator_test.rs:9:5: 9:35
diff --git a/src/test/mir-opt/deaggregator_test_enum.bar.Deaggregator.diff b/src/test/mir-opt/deaggregator_test_enum.bar.Deaggregator.diff
index 5af9a536693..b28f506a694 100644
--- a/src/test/mir-opt/deaggregator_test_enum.bar.Deaggregator.diff
+++ b/src/test/mir-opt/deaggregator_test_enum.bar.Deaggregator.diff
@@ -10,6 +10,7 @@
           StorageLive(_2);                 // scope 0 at $DIR/deaggregator_test_enum.rs:8:19: 8:20
           _2 = _1;                         // scope 0 at $DIR/deaggregator_test_enum.rs:8:19: 8:20
 -         _0 = Baz::Foo { x: move _2 };    // scope 0 at $DIR/deaggregator_test_enum.rs:8:5: 8:22
++         Deinit(_0);                      // scope 0 at $DIR/deaggregator_test_enum.rs:8:5: 8:22
 +         ((_0 as Foo).0: usize) = move _2; // scope 0 at $DIR/deaggregator_test_enum.rs:8:5: 8:22
 +         discriminant(_0) = 1;            // scope 0 at $DIR/deaggregator_test_enum.rs:8:5: 8:22
           StorageDead(_2);                 // scope 0 at $DIR/deaggregator_test_enum.rs:8:21: 8:22
diff --git a/src/test/mir-opt/deaggregator_test_enum_2.test1.Deaggregator.diff b/src/test/mir-opt/deaggregator_test_enum_2.test1.Deaggregator.diff
index 629bed8fec5..5cfcef849e9 100644
--- a/src/test/mir-opt/deaggregator_test_enum_2.test1.Deaggregator.diff
+++ b/src/test/mir-opt/deaggregator_test_enum_2.test1.Deaggregator.diff
@@ -19,6 +19,7 @@
           StorageLive(_4);                 // scope 0 at $DIR/deaggregator_test_enum_2.rs:11:16: 11:17
           _4 = _2;                         // scope 0 at $DIR/deaggregator_test_enum_2.rs:11:16: 11:17
 -         _0 = Foo::A(move _4);            // scope 0 at $DIR/deaggregator_test_enum_2.rs:11:9: 11:18
++         Deinit(_0);                      // scope 0 at $DIR/deaggregator_test_enum_2.rs:11:9: 11:18
 +         ((_0 as A).0: i32) = move _4;    // scope 0 at $DIR/deaggregator_test_enum_2.rs:11:9: 11:18
 +         discriminant(_0) = 0;            // scope 0 at $DIR/deaggregator_test_enum_2.rs:11:9: 11:18
           StorageDead(_4);                 // scope 0 at $DIR/deaggregator_test_enum_2.rs:11:17: 11:18
@@ -29,6 +30,7 @@
           StorageLive(_5);                 // scope 0 at $DIR/deaggregator_test_enum_2.rs:13:16: 13:17
           _5 = _2;                         // scope 0 at $DIR/deaggregator_test_enum_2.rs:13:16: 13:17
 -         _0 = Foo::B(move _5);            // scope 0 at $DIR/deaggregator_test_enum_2.rs:13:9: 13:18
++         Deinit(_0);                      // scope 0 at $DIR/deaggregator_test_enum_2.rs:13:9: 13:18
 +         ((_0 as B).0: i32) = move _5;    // scope 0 at $DIR/deaggregator_test_enum_2.rs:13:9: 13:18
 +         discriminant(_0) = 1;            // scope 0 at $DIR/deaggregator_test_enum_2.rs:13:9: 13:18
           StorageDead(_5);                 // scope 0 at $DIR/deaggregator_test_enum_2.rs:13:17: 13:18
diff --git a/src/test/mir-opt/deaggregator_test_multiple.test.Deaggregator.diff b/src/test/mir-opt/deaggregator_test_multiple.test.Deaggregator.diff
index f5d8d0607c6..c346f551a1a 100644
--- a/src/test/mir-opt/deaggregator_test_multiple.test.Deaggregator.diff
+++ b/src/test/mir-opt/deaggregator_test_multiple.test.Deaggregator.diff
@@ -14,6 +14,7 @@
           StorageLive(_3);                 // scope 0 at $DIR/deaggregator_test_multiple.rs:10:13: 10:14
           _3 = _1;                         // scope 0 at $DIR/deaggregator_test_multiple.rs:10:13: 10:14
 -         _2 = Foo::A(move _3);            // scope 0 at $DIR/deaggregator_test_multiple.rs:10:6: 10:15
++         Deinit(_2);                      // scope 0 at $DIR/deaggregator_test_multiple.rs:10:6: 10:15
 +         ((_2 as A).0: i32) = move _3;    // scope 0 at $DIR/deaggregator_test_multiple.rs:10:6: 10:15
 +         discriminant(_2) = 0;            // scope 0 at $DIR/deaggregator_test_multiple.rs:10:6: 10:15
           StorageDead(_3);                 // scope 0 at $DIR/deaggregator_test_multiple.rs:10:14: 10:15
@@ -21,6 +22,7 @@
           StorageLive(_5);                 // scope 0 at $DIR/deaggregator_test_multiple.rs:10:24: 10:25
           _5 = _1;                         // scope 0 at $DIR/deaggregator_test_multiple.rs:10:24: 10:25
 -         _4 = Foo::A(move _5);            // scope 0 at $DIR/deaggregator_test_multiple.rs:10:17: 10:26
++         Deinit(_4);                      // scope 0 at $DIR/deaggregator_test_multiple.rs:10:17: 10:26
 +         ((_4 as A).0: i32) = move _5;    // scope 0 at $DIR/deaggregator_test_multiple.rs:10:17: 10:26
 +         discriminant(_4) = 0;            // scope 0 at $DIR/deaggregator_test_multiple.rs:10:17: 10:26
           StorageDead(_5);                 // scope 0 at $DIR/deaggregator_test_multiple.rs:10:25: 10:26
diff --git a/src/test/mir-opt/derefer_test.main.Derefer.diff b/src/test/mir-opt/derefer_test.main.Derefer.diff
index e9a45656ebf..d58e4eb838d 100644
--- a/src/test/mir-opt/derefer_test.main.Derefer.diff
+++ b/src/test/mir-opt/derefer_test.main.Derefer.diff
@@ -25,11 +25,13 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/derefer_test.rs:3:9: 3:14
+          Deinit(_1);                      // scope 0 at $DIR/derefer_test.rs:3:17: 3:24
           (_1.0: i32) = const 42_i32;      // scope 0 at $DIR/derefer_test.rs:3:17: 3:24
           (_1.1: i32) = const 43_i32;      // scope 0 at $DIR/derefer_test.rs:3:17: 3:24
           StorageLive(_2);                 // scope 1 at $DIR/derefer_test.rs:4:9: 4:14
           StorageLive(_3);                 // scope 1 at $DIR/derefer_test.rs:4:22: 4:28
           _3 = &mut _1;                    // scope 1 at $DIR/derefer_test.rs:4:22: 4:28
+          Deinit(_2);                      // scope 1 at $DIR/derefer_test.rs:4:17: 4:29
           (_2.0: i32) = const 99_i32;      // scope 1 at $DIR/derefer_test.rs:4:17: 4:29
           (_2.1: &mut (i32, i32)) = move _3; // scope 1 at $DIR/derefer_test.rs:4:17: 4:29
           StorageDead(_3);                 // scope 1 at $DIR/derefer_test.rs:4:28: 4:29
diff --git a/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff
new file mode 100644
index 00000000000..db24f71c750
--- /dev/null
+++ b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff
@@ -0,0 +1,104 @@
+- // MIR for `main` before Derefer
++ // MIR for `main` after Derefer
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/derefer_test_multiple.rs:2:12: 2:12
+      let mut _1: (i32, i32);              // in scope 0 at $DIR/derefer_test_multiple.rs:3:9: 3:14
+      let mut _3: &mut (i32, i32);         // in scope 0 at $DIR/derefer_test_multiple.rs:4:22: 4:28
+      let mut _5: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:5:22: 5:28
+      let mut _7: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:6:22: 6:28
++     let mut _10: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++     let mut _11: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++     let mut _12: &mut (i32, i32);        // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++     let mut _13: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++     let mut _14: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++     let mut _15: &mut (i32, i32);        // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/derefer_test_multiple.rs:3:9: 3:14
+          let mut _2: (i32, &mut (i32, i32)); // in scope 1 at $DIR/derefer_test_multiple.rs:4:9: 4:14
+          scope 2 {
+              debug b => _2;               // in scope 2 at $DIR/derefer_test_multiple.rs:4:9: 4:14
+              let mut _4: (i32, &mut (i32, &mut (i32, i32))); // in scope 2 at $DIR/derefer_test_multiple.rs:5:9: 5:14
+              scope 3 {
+                  debug c => _4;           // in scope 3 at $DIR/derefer_test_multiple.rs:5:9: 5:14
+                  let mut _6: (i32, &mut (i32, &mut (i32, &mut (i32, i32)))); // in scope 3 at $DIR/derefer_test_multiple.rs:6:9: 6:14
+                  scope 4 {
+                      debug d => _6;       // in scope 4 at $DIR/derefer_test_multiple.rs:6:9: 6:14
+                      let _8: &mut i32;    // in scope 4 at $DIR/derefer_test_multiple.rs:7:9: 7:10
+                      scope 5 {
+                          debug x => _8;   // in scope 5 at $DIR/derefer_test_multiple.rs:7:9: 7:10
+                          let _9: &mut i32; // in scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
+                          scope 6 {
+                              debug y => _9; // in scope 6 at $DIR/derefer_test_multiple.rs:8:9: 8:10
+                          }
+                      }
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/derefer_test_multiple.rs:3:9: 3:14
+          Deinit(_1);                      // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25
+          (_1.0: i32) = const 42_i32;      // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25
+          (_1.1: i32) = const 43_i32;      // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25
+          StorageLive(_2);                 // scope 1 at $DIR/derefer_test_multiple.rs:4:9: 4:14
+          StorageLive(_3);                 // scope 1 at $DIR/derefer_test_multiple.rs:4:22: 4:28
+          _3 = &mut _1;                    // scope 1 at $DIR/derefer_test_multiple.rs:4:22: 4:28
+          Deinit(_2);                      // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29
+          (_2.0: i32) = const 99_i32;      // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29
+          (_2.1: &mut (i32, i32)) = move _3; // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29
+          StorageDead(_3);                 // scope 1 at $DIR/derefer_test_multiple.rs:4:28: 4:29
+          StorageLive(_4);                 // scope 2 at $DIR/derefer_test_multiple.rs:5:9: 5:14
+          StorageLive(_5);                 // scope 2 at $DIR/derefer_test_multiple.rs:5:22: 5:28
+          _5 = &mut _2;                    // scope 2 at $DIR/derefer_test_multiple.rs:5:22: 5:28
+          Deinit(_4);                      // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29
+          (_4.0: i32) = const 11_i32;      // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29
+          (_4.1: &mut (i32, &mut (i32, i32))) = move _5; // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29
+          StorageDead(_5);                 // scope 2 at $DIR/derefer_test_multiple.rs:5:28: 5:29
+          StorageLive(_6);                 // scope 3 at $DIR/derefer_test_multiple.rs:6:9: 6:14
+          StorageLive(_7);                 // scope 3 at $DIR/derefer_test_multiple.rs:6:22: 6:28
+          _7 = &mut _4;                    // scope 3 at $DIR/derefer_test_multiple.rs:6:22: 6:28
+          Deinit(_6);                      // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29
+          (_6.0: i32) = const 13_i32;      // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29
+          (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))) = move _7; // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29
+          StorageDead(_7);                 // scope 3 at $DIR/derefer_test_multiple.rs:6:28: 6:29
+          StorageLive(_8);                 // scope 4 at $DIR/derefer_test_multiple.rs:7:9: 7:10
+-         _8 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         StorageLive(_10);                // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         _10 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         StorageLive(_11);                // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         _11 = move ((*_10).1: &mut (i32, &mut (i32, i32))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         StorageLive(_12);                // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         _12 = move ((*_11).1: &mut (i32, i32)); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         _8 = &mut ((*_12).1: i32);       // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         StorageDead(_10);                // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
++         StorageDead(_11);                // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
++         StorageDead(_12);                // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
+          StorageLive(_9);                 // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
+-         _9 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         StorageLive(_13);                // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         _13 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         StorageLive(_14);                // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         _14 = move ((*_13).1: &mut (i32, &mut (i32, i32))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         StorageLive(_15);                // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         _15 = move ((*_14).1: &mut (i32, i32)); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         _9 = &mut ((*_15).1: i32);       // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         StorageDead(_13);                // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2
++         StorageDead(_14);                // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2
++         StorageDead(_15);                // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2
+          _0 = const ();                   // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2
+          StorageDead(_9);                 // scope 5 at $DIR/derefer_test_multiple.rs:9:1: 9:2
+          StorageDead(_8);                 // scope 4 at $DIR/derefer_test_multiple.rs:9:1: 9:2
+          StorageDead(_6);                 // scope 3 at $DIR/derefer_test_multiple.rs:9:1: 9:2
+          StorageDead(_4);                 // scope 2 at $DIR/derefer_test_multiple.rs:9:1: 9:2
+          StorageDead(_2);                 // scope 1 at $DIR/derefer_test_multiple.rs:9:1: 9:2
+          StorageDead(_1);                 // scope 0 at $DIR/derefer_test_multiple.rs:9:1: 9:2
+          return;                          // scope 0 at $DIR/derefer_test_multiple.rs:9:2: 9:2
++     }
++ 
++     bb1 (cleanup): {
++         resume;                          // scope 0 at $DIR/derefer_test_multiple.rs:2:1: 9:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/derefer_test_multiple.rs b/src/test/mir-opt/derefer_test_multiple.rs
new file mode 100644
index 00000000000..a27363447fe
--- /dev/null
+++ b/src/test/mir-opt/derefer_test_multiple.rs
@@ -0,0 +1,9 @@
+// EMIT_MIR derefer_test_multiple.main.Derefer.diff
+fn main () {
+    let mut a = (42, 43);
+    let mut b = (99, &mut a);
+    let mut c = (11, &mut b);
+    let mut d = (13, &mut c);
+    let x = &mut (*d.1).1.1.1;
+    let y = &mut (*d.1).1.1.1;
+}
diff --git a/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff
index ab60a7fc62f..9330e68b1aa 100644
--- a/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff
+++ b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff
@@ -29,6 +29,7 @@
       }
   
       bb1: {
+          Deinit(_1);                      // scope 0 at $DIR/union.rs:13:14: 13:30
 -         (_1.0: u32) = move _2;           // scope 0 at $DIR/union.rs:13:14: 13:30
 -         StorageDead(_2);                 // scope 0 at $DIR/union.rs:13:29: 13:30
 +         nop;                             // scope 0 at $DIR/union.rs:13:14: 13:30
diff --git a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
index 3fe23633852..e40274dc393 100644
--- a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
@@ -25,6 +25,7 @@
           _4 = _1;                         // scope 0 at $DIR/early_otherwise_branch.rs:4:12: 4:13
           StorageLive(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:4:15: 4:16
           _5 = _2;                         // scope 0 at $DIR/early_otherwise_branch.rs:4:15: 4:16
+          Deinit(_3);                      // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17
           (_3.0: std::option::Option<u32>) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17
           (_3.1: std::option::Option<u32>) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:4:16: 4:17
diff --git a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
index 79b923a2889..4f2b9696f8c 100644
--- a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
@@ -26,6 +26,7 @@
           _4 = _1;                         // scope 0 at $DIR/early_otherwise_branch.rs:12:12: 12:13
           StorageLive(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:12:15: 12:16
           _5 = _2;                         // scope 0 at $DIR/early_otherwise_branch.rs:12:15: 12:16
+          Deinit(_3);                      // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17
           (_3.0: std::option::Option<u32>) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17
           (_3.1: std::option::Option<u32>) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:12:16: 12:17
diff --git a/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
index 2aa22737bde..96c7e46853f 100644
--- a/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
@@ -25,6 +25,7 @@
           _4 = _1;                         // scope 0 at $DIR/early_otherwise_branch.rs:22:12: 22:13
           StorageLive(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:22:15: 22:16
           _5 = _2;                         // scope 0 at $DIR/early_otherwise_branch.rs:22:15: 22:16
+          Deinit(_3);                      // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17
           (_3.0: std::option::Option<u32>) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17
           (_3.1: std::option::Option<bool>) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:22:16: 22:17
diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
index 8b78f3ce202..379d0e9ea48 100644
--- a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
@@ -34,6 +34,7 @@
           _6 = _2;                         // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:15: 5:16
           StorageLive(_7);                 // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:18: 5:19
           _7 = _3;                         // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:18: 5:19
+          Deinit(_4);                      // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20
           (_4.0: std::option::Option<u32>) = move _5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20
           (_4.1: std::option::Option<u32>) = move _6; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20
           (_4.2: std::option::Option<u32>) = move _7; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20
diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff
index db6794db298..592388e69a9 100644
--- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff
+++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff
@@ -74,6 +74,7 @@
 +         (_4.0: &ViewportPercentageLength) = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16
           StorageLive(_6);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:18: 21:23
           _6 = _2;                         // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:18: 21:23
+          Deinit(_4);                      // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
 -         (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
 +         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
@@ -98,6 +99,8 @@
 -     bb2: {
 +         StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
           StorageLive(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
+-         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
+          Deinit(_0);                      // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
 -         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
           discriminant(_0) = 1;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
           StorageDead(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:27: 26:28
@@ -121,6 +124,7 @@
 +         ((((_0 as Ok).0: ViewportPercentageLength) as Vw).0: f32) = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
 +         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
 +         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
++         Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
 +         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
 +         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
 +         nop;                             // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
@@ -144,6 +148,7 @@
 +         ((((_0 as Ok).0: ViewportPercentageLength) as Vh).0: f32) = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
 +         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
 +         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
++         Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
 +         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
 +         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
 +         nop;                             // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
@@ -167,6 +172,7 @@
 +         ((((_0 as Ok).0: ViewportPercentageLength) as Vmin).0: f32) = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
 +         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
 +         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
++         Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
 +         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
 +         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
 +         nop;                             // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
@@ -190,6 +196,7 @@
 +         ((((_0 as Ok).0: ViewportPercentageLength) as Vmax).0: f32) = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
 +         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
 +         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
++         Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
 +         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
 +         discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
 +         nop;                             // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
@@ -211,6 +218,7 @@
 -         _14 = Add(move _15, move _16);   // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
 -         StorageDead(_16);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
 -         StorageDead(_15);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
+-         Deinit(_3);                      // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
 -         ((_3 as Vw).0: f32) = move _14;  // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
 -         discriminant(_3) = 0;            // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
 -         StorageDead(_14);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
@@ -232,6 +240,7 @@
 -         _19 = Add(move _20, move _21);   // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
 -         StorageDead(_21);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
 -         StorageDead(_20);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
+-         Deinit(_3);                      // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
 -         ((_3 as Vh).0: f32) = move _19;  // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
 -         discriminant(_3) = 1;            // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
 -         StorageDead(_19);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
@@ -253,6 +262,7 @@
 -         _24 = Add(move _25, move _26);   // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
 -         StorageDead(_26);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
 -         StorageDead(_25);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
+-         Deinit(_3);                      // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
 -         ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
 -         discriminant(_3) = 2;            // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
 -         StorageDead(_24);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
@@ -274,6 +284,7 @@
 -         _29 = Add(move _30, move _31);   // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
 -         StorageDead(_31);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
 -         StorageDead(_30);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
+-         Deinit(_3);                      // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
 -         ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
 -         discriminant(_3) = 3;            // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
 -         StorageDead(_29);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
@@ -283,6 +294,7 @@
 -     }
 - 
 -     bb10: {
+          Deinit(_0);                      // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
 -         ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
 +         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
           discriminant(_0) = 0;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
index c8d8ae7766d..4cd34ba38ba 100644
--- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
@@ -62,6 +62,7 @@
           _5 = _1;                         // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:15: 21:16
           StorageLive(_6);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:18: 21:23
           _6 = _2;                         // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:18: 21:23
+          Deinit(_4);                      // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:14: 21:24
           StorageDead(_6);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:23: 21:24
@@ -84,6 +85,8 @@
 -     bb2: {
 +         StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
           StorageLive(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
+-         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
+          Deinit(_0);                      // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
 -         nop;                             // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
           discriminant(_0) = 1;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:21: 26:28
           StorageDead(_33);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:27: 26:28
@@ -121,6 +124,7 @@
           _14 = Add(move _15, move _16);   // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:38: 22:49
           StorageDead(_16);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
           StorageDead(_15);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:48: 22:49
+          Deinit(_3);                      // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
           ((_3 as Vw).0: f32) = move _14;  // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
           discriminant(_3) = 0;            // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:35: 22:50
           StorageDead(_14);                // scope 1 at $DIR/early_otherwise_branch_68867.rs:22:49: 22:50
@@ -144,6 +148,7 @@
           _19 = Add(move _20, move _21);   // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49
           StorageDead(_21);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
           StorageDead(_20);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49
+          Deinit(_3);                      // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
           ((_3 as Vh).0: f32) = move _19;  // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
           discriminant(_3) = 1;            // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50
           StorageDead(_19);                // scope 2 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50
@@ -167,6 +172,7 @@
           _24 = Add(move _25, move _26);   // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:55
           StorageDead(_26);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
           StorageDead(_25);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:54: 24:55
+          Deinit(_3);                      // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
           ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
           discriminant(_3) = 2;            // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:39: 24:56
           StorageDead(_24);                // scope 3 at $DIR/early_otherwise_branch_68867.rs:24:55: 24:56
@@ -190,6 +196,7 @@
           _29 = Add(move _30, move _31);   // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55
           StorageDead(_31);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
           StorageDead(_30);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55
+          Deinit(_3);                      // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
           ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
           discriminant(_3) = 3;            // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56
           StorageDead(_29);                // scope 4 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56
@@ -201,6 +208,7 @@
   
 -     bb10: {
 +     bb6: {
+          Deinit(_0);                      // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
           ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
           discriminant(_0) = 0;            // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:5: 27:7
           StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff
index 5343f22d3da..6adc5194aec 100644
--- a/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff
@@ -32,6 +32,7 @@
           _4 = _1;                         // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:12: 8:13
           StorageLive(_5);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:15: 8:16
           _5 = _2;                         // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:15: 8:16
+          Deinit(_3);                      // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
           (_3.0: std::option::Option<u32>) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
           (_3.1: std::option::Option<u32>) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
           StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:16: 8:17
diff --git a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff
index 92024692472..f22fbec03d0 100644
--- a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff
+++ b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff
@@ -51,11 +51,13 @@
       }
   
       bb2: {
+          Deinit(_6);                      // scope 1 at $DIR/funky_arms.rs:21:17: 21:41
           discriminant(_6) = 1;            // scope 1 at $DIR/funky_arms.rs:21:17: 21:41
           goto -> bb4;                     // scope 1 at $DIR/funky_arms.rs:21:17: 21:41
       }
   
       bb3: {
+          Deinit(_6);                      // scope 1 at $DIR/funky_arms.rs:20:18: 20:38
           discriminant(_6) = 0;            // scope 1 at $DIR/funky_arms.rs:20:18: 20:38
           goto -> bb4;                     // scope 1 at $DIR/funky_arms.rs:20:18: 20:38
       }
diff --git a/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir b/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir
index 642d9b3fb35..739492d7d24 100644
--- a/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir
+++ b/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir
@@ -21,11 +21,14 @@ yields ()
 
     bb0: {
         StorageLive(_3);                 // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:13: 23:14
+        Deinit(_3);                      // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23
         (_3.0: i32) = const 5_i32;       // scope 0 at $DIR/generator-storage-dead-unwind.rs:23:17: 23:23
         StorageLive(_4);                 // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:13: 24:14
+        Deinit(_4);                      // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23
         (_4.0: i32) = const 6_i32;       // scope 1 at $DIR/generator-storage-dead-unwind.rs:24:17: 24:23
         StorageLive(_5);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
         StorageLive(_6);                 // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
+        Deinit(_6);                      // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
         _5 = yield(move _6) -> [resume: bb1, drop: bb5]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:25:9: 25:14
     }
 
diff --git a/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
index 539988cad24..7f5ebe2a59b 100644
--- a/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
+++ b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
@@ -1,13 +1,17 @@
 // MIR for `main::{closure#0}` 0 generator_resume
 /* generator_layout = GeneratorLayout {
-    field_tys: {},
+    field_tys: {
+        _0: HasDrop,
+    },
     variant_fields: {
         Unresumed(0): [],
         Returned (1): [],
         Panicked (2): [],
-        Suspend0 (3): [],
+        Suspend0 (3): [_0],
+    },
+    storage_conflicts: BitMatrix(1x1) {
+        (_0, _0),
     },
-    storage_conflicts: BitMatrix(0x0) {},
 } */
 
 fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]>, _2: u8) -> GeneratorState<(), ()> {
@@ -23,7 +27,7 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]
     let _10: u8;                         // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19
     let mut _11: u32;                    // in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
     scope 1 {
-        debug _d => _3;                  // in scope 1 at $DIR/generator-tiny.rs:20:13: 20:15
+        debug _d => (((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6])) as variant#3).0: HasDrop); // in scope 1 at $DIR/generator-tiny.rs:20:13: 20:15
     }
 
     bb0: {
@@ -33,7 +37,8 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]
 
     bb1: {
         _10 = move _2;                   // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
-        StorageLive(_3);                 // scope 0 at $DIR/generator-tiny.rs:20:13: 20:15
+        nop;                             // scope 0 at $DIR/generator-tiny.rs:20:13: 20:15
+        Deinit((((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6])) as variant#3).0: HasDrop)); // scope 0 at $DIR/generator-tiny.rs:20:18: 20:25
         StorageLive(_4);                 // scope 1 at $DIR/generator-tiny.rs:21:9: 24:10
         goto -> bb2;                     // scope 1 at $DIR/generator-tiny.rs:21:9: 24:10
     }
@@ -41,6 +46,8 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]
     bb2: {
         StorageLive(_6);                 // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         StorageLive(_7);                 // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
+        Deinit(_7);                      // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
+        Deinit(_0);                      // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         ((_0 as Yielded).0: ()) = move _7; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         discriminant(_0) = 0;            // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]))) = 3; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
@@ -64,7 +71,6 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]
     }
 
     bb5: {
-        StorageLive(_3);                 // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
         StorageLive(_4);                 // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
         StorageLive(_6);                 // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
         StorageLive(_7);                 // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
diff --git a/src/test/mir-opt/inline/cycle.f.Inline.diff b/src/test/mir-opt/inline/cycle.f.Inline.diff
index 5624e379bfd..d42b8397c50 100644
--- a/src/test/mir-opt/inline/cycle.f.Inline.diff
+++ b/src/test/mir-opt/inline/cycle.f.Inline.diff
@@ -13,6 +13,7 @@
           StorageLive(_3);                 // scope 0 at $DIR/cycle.rs:6:5: 6:6
           _3 = &_1;                        // scope 0 at $DIR/cycle.rs:6:5: 6:6
           StorageLive(_4);                 // scope 0 at $DIR/cycle.rs:6:5: 6:8
+          Deinit(_4);                      // scope 0 at $DIR/cycle.rs:6:5: 6:8
           _2 = <impl Fn() as Fn<()>>::call(move _3, move _4) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/cycle.rs:6:5: 6:8
                                            // mir::Constant
                                            // + span: $DIR/cycle.rs:6:5: 6:6
diff --git a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir
index 93a63c84783..4d6cdafd12d 100644
--- a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir
@@ -21,6 +21,7 @@ fn foo(_1: T, _2: i32) -> i32 {
 
     bb0: {
         StorageLive(_3);                 // scope 0 at $DIR/inline-closure.rs:11:9: 11:10
+        Deinit(_3);                      // scope 0 at $DIR/inline-closure.rs:11:13: 11:24
         StorageLive(_4);                 // scope 1 at $DIR/inline-closure.rs:12:5: 12:6
         _4 = &_3;                        // scope 1 at $DIR/inline-closure.rs:12:5: 12:6
         StorageLive(_5);                 // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
@@ -28,6 +29,7 @@ fn foo(_1: T, _2: i32) -> i32 {
         _6 = _2;                         // scope 1 at $DIR/inline-closure.rs:12:7: 12:8
         StorageLive(_7);                 // scope 1 at $DIR/inline-closure.rs:12:10: 12:11
         _7 = _2;                         // scope 1 at $DIR/inline-closure.rs:12:10: 12:11
+        Deinit(_5);                      // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
         (_5.0: i32) = move _6;           // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
         (_5.1: i32) = move _7;           // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
         StorageLive(_8);                 // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
diff --git a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
index 3436370253f..45281302f92 100644
--- a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
@@ -25,6 +25,7 @@ fn foo(_1: T, _2: &i32) -> i32 {
 
     bb0: {
         StorageLive(_3);                 // scope 0 at $DIR/inline-closure-borrows-arg.rs:12:9: 12:10
+        Deinit(_3);                      // scope 0 at $DIR/inline-closure-borrows-arg.rs:12:13: 15:6
         StorageLive(_4);                 // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:6
         _4 = &_3;                        // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:6
         StorageLive(_5);                 // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
@@ -32,6 +33,7 @@ fn foo(_1: T, _2: &i32) -> i32 {
         _6 = &(*_2);                     // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:7: 16:8
         StorageLive(_7);                 // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11
         _7 = &(*_2);                     // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11
+        Deinit(_5);                      // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
         (_5.0: &i32) = move _6;          // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
         (_5.1: &i32) = move _7;          // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
         StorageLive(_8);                 // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
diff --git a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
index cb382859d51..337f0871843 100644
--- a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
@@ -28,6 +28,7 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
         _4 = &_2;                        // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24
         StorageLive(_5);                 // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24
         _5 = &_1;                        // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24
+        Deinit(_3);                      // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24
         (_3.0: &i32) = move _4;          // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24
         (_3.1: &T) = move _5;            // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24
         StorageDead(_5);                 // scope 0 at $DIR/inline-closure-captures.rs:11:23: 11:24
@@ -37,6 +38,7 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
         StorageLive(_7);                 // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
         StorageLive(_8);                 // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8
         _8 = _2;                         // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8
+        Deinit(_7);                      // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
         (_7.0: i32) = move _8;           // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
         StorageLive(_9);                 // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
         _9 = move (_7.0: i32);           // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
@@ -44,6 +46,7 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
         _10 = (*((*_6).0: &i32));        // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
         StorageLive(_11);                // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
         _11 = (*((*_6).1: &T));          // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
+        Deinit(_0);                      // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
         (_0.0: i32) = move _10;          // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
         (_0.1: T) = move _11;            // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
         StorageDead(_11);                // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24
diff --git a/src/test/mir-opt/inline/inline_generator.main.Inline.diff b/src/test/mir-opt/inline/inline_generator.main.Inline.diff
index 831d73045dd..48432c1ddd8 100644
--- a/src/test/mir-opt/inline/inline_generator.main.Inline.diff
+++ b/src/test/mir-opt/inline/inline_generator.main.Inline.diff
@@ -44,6 +44,7 @@
 -     }
 - 
 -     bb1: {
++         Deinit(_4);                      // scope 2 at $DIR/inline-generator.rs:15:5: 15:41
 +         discriminant(_4) = 0;            // scope 2 at $DIR/inline-generator.rs:15:5: 15:41
           _3 = &mut _4;                    // scope 0 at $DIR/inline-generator.rs:9:23: 9:31
 -         _2 = Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new(move _3) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:32
@@ -58,6 +59,7 @@
 +         _5 = move _3;                    // scope 4 at $SRC_DIR/core/src/pin.rs:LL:COL
 +         StorageLive(_6);                 // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
 +         _6 = move _5;                    // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
++         Deinit(_2);                      // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
 +         (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]) = move _6; // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
 +         StorageDead(_6);                 // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
 +         StorageDead(_5);                 // scope 4 at $SRC_DIR/core/src/pin.rs:LL:COL
@@ -113,6 +115,7 @@
 + 
 +     bb6: {
 +         StorageDead(_9);                 // scope 6 at $DIR/inline-generator.rs:15:38: 15:39
++         Deinit(_1);                      // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
 +         ((_1 as Yielded).0: i32) = move _8; // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
 +         discriminant(_1) = 0;            // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
 +         discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]))) = 3; // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
@@ -123,6 +126,7 @@
 +         StorageLive(_8);                 // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
 +         _10 = move _7;                   // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
 +         StorageDead(_8);                 // scope 6 at $DIR/inline-generator.rs:15:38: 15:39
++         Deinit(_1);                      // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
 +         ((_1 as Complete).0: bool) = move _10; // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
 +         discriminant(_1) = 1;            // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
 +         discriminant((*(_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]))) = 1; // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
index 5903cdd9489..072ab5e8df4 100644
--- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
+++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
@@ -34,6 +34,7 @@
 -         (*_5) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         StorageLive(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         _7 = &mut (*_5);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
++         Deinit((*_7));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +         ((*_7).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: {0x4 as *const u32}, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
                                            // mir::Constant
 -                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
index 0f83b0c4a27..8b8a741ec12 100644
--- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
+++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
@@ -34,6 +34,7 @@
 -         (*_5) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         StorageLive(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         _7 = &mut (*_5);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
++         Deinit((*_7));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +         ((*_7).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: {0x4 as *const u32}, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
                                            // mir::Constant
 -                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
diff --git a/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir b/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir
index 42704b06883..b9ddbacc0e7 100644
--- a/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir
+++ b/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir
@@ -20,10 +20,13 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:5:9: 5:10
+        Deinit(_1);                      // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:5:13: 5:33
         StorageLive(_2);                 // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:6
         _2 = &_1;                        // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:6
         StorageLive(_3);                 // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10
         StorageLive(_4);                 // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:7: 6:9
+        Deinit(_4);                      // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:7: 6:9
+        Deinit(_3);                      // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10
         (_3.0: ()) = move _4;            // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10
         StorageLive(_5);                 // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10
         _5 = move (_3.0: ());            // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10
diff --git a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff
index ea6b91cba9e..b44f9900d6c 100644
--- a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff
+++ b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff
@@ -25,6 +25,7 @@
       bb1: {
           _3 = &_4;                        // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
           StorageLive(_5);                 // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+          Deinit(_5);                      // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
 -         _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
 -                                          // mir::Constant
 -                                          // + span: $DIR/issue-78442.rs:11:5: 11:15
diff --git a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff
index ba9da7678e7..8a998fb5000 100644
--- a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff
+++ b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff
@@ -24,7 +24,7 @@
       bb1: {
           _3 = &_4;                        // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
           StorageLive(_5);                 // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
-          nop;                             // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+          Deinit(_5);                      // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
 -         _2 = <impl Fn() as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
 +         _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
                                            // mir::Constant
diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
index 240da5577de..288250e8afd 100644
--- a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
+++ b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
@@ -43,6 +43,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:2:9: 2:14
           StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+          Deinit(_2);                      // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
           ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
           discriminant(_2) = 1;            // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
           StorageLive(_3);                 // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
@@ -53,6 +54,7 @@
           StorageLive(_4);                 // scope 1 at $DIR/issue-73223.rs:7:9: 7:14
           StorageLive(_5);                 // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
           _5 = _1;                         // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
+          Deinit(_4);                      // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
           ((_4 as Some).0: i32) = move _5; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
           discriminant(_4) = 1;            // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
           StorageDead(_5);                 // scope 1 at $DIR/issue-73223.rs:7:27: 7:28
@@ -65,6 +67,7 @@
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
           _8 = _20;                        // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_6);                      // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_6.0: &i32) = move _7;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_6.1: &i32) = move _8;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -86,6 +89,7 @@
   
       bb1: {
           StorageLive(_14);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_14);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           discriminant(_14) = 0;           // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_15);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_16);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -96,6 +100,7 @@
           _18 = _10;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _17 = _18;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_19);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_19);                     // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           discriminant(_19) = 0;           // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _15, move _17, move _19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // mir::Constant
diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
index 240da5577de..288250e8afd 100644
--- a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
+++ b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
@@ -43,6 +43,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:2:9: 2:14
           StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+          Deinit(_2);                      // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
           ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
           discriminant(_2) = 1;            // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
           StorageLive(_3);                 // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
@@ -53,6 +54,7 @@
           StorageLive(_4);                 // scope 1 at $DIR/issue-73223.rs:7:9: 7:14
           StorageLive(_5);                 // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
           _5 = _1;                         // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
+          Deinit(_4);                      // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
           ((_4 as Some).0: i32) = move _5; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
           discriminant(_4) = 1;            // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
           StorageDead(_5);                 // scope 1 at $DIR/issue-73223.rs:7:27: 7:28
@@ -65,6 +67,7 @@
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
           _8 = _20;                        // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_6);                      // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_6.0: &i32) = move _7;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_6.1: &i32) = move _8;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -86,6 +89,7 @@
   
       bb1: {
           StorageLive(_14);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_14);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           discriminant(_14) = 0;           // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_15);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_16);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -96,6 +100,7 @@
           _18 = _10;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _17 = _18;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_19);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_19);                     // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           discriminant(_19) = 0;           // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _15, move _17, move _19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // mir::Constant
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
index 1e8b681dfad..89c7154ae00 100644
--- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
+++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
@@ -51,6 +51,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:2:9: 2:14
           StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+          Deinit(_2);                      // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
           ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
           discriminant(_2) = 1;            // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
           _3 = const 1_isize;              // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
@@ -73,6 +74,7 @@
           StorageLive(_6);                 // scope 1 at $DIR/issue-73223.rs:7:9: 7:14
           StorageLive(_7);                 // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
           _7 = _1;                         // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
+          Deinit(_6);                      // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
           ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
           discriminant(_6) = 1;            // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
           StorageDead(_7);                 // scope 1 at $DIR/issue-73223.rs:7:27: 7:28
@@ -86,6 +88,7 @@
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
           _11 = _28;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_9);                      // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_9.0: &i32) = move _10;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_9.1: &i32) = move _11;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_11);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -110,6 +113,7 @@
   
       bb3: {
           StorageLive(_20);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_20);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           discriminant(_20) = 0;           // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_21);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_22);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -126,6 +130,7 @@
           _26 = _14;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _25 = _26;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_27);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_27);                     // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           discriminant(_27) = 0;           // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _23, move _25, move _27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // mir::Constant
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
index 1e8b681dfad..89c7154ae00 100644
--- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
+++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
@@ -51,6 +51,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:2:9: 2:14
           StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
+          Deinit(_2);                      // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
           ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
           discriminant(_2) = 1;            // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
           _3 = const 1_isize;              // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
@@ -73,6 +74,7 @@
           StorageLive(_6);                 // scope 1 at $DIR/issue-73223.rs:7:9: 7:14
           StorageLive(_7);                 // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
           _7 = _1;                         // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
+          Deinit(_6);                      // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
           ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
           discriminant(_6) = 1;            // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
           StorageDead(_7);                 // scope 1 at $DIR/issue-73223.rs:7:27: 7:28
@@ -86,6 +88,7 @@
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
           _11 = _28;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_9);                      // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_9.0: &i32) = move _10;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_9.1: &i32) = move _11;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_11);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -110,6 +113,7 @@
   
       bb3: {
           StorageLive(_20);                // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_20);                     // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           discriminant(_20) = 0;           // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_21);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_22);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -126,6 +130,7 @@
           _26 = _14;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _25 = _26;                       // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_27);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          Deinit(_27);                     // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           discriminant(_27) = 0;           // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _23, move _25, move _27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // mir::Constant
diff --git a/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
index 39448a16f1a..299529ec649 100644
--- a/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
+++ b/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
@@ -67,6 +67,7 @@
   
       bb7: {
           StorageDead(_6);                 // scope 4 at $DIR/issue-75439.rs:10:35: 10:36
+          Deinit(_0);                      // scope 1 at $DIR/issue-75439.rs:10:9: 10:39
           ((_0 as Some).0: [u8; 4]) = move _5; // scope 1 at $DIR/issue-75439.rs:10:9: 10:39
           discriminant(_0) = 1;            // scope 1 at $DIR/issue-75439.rs:10:9: 10:39
           StorageDead(_5);                 // scope 1 at $DIR/issue-75439.rs:10:38: 10:39
@@ -75,6 +76,7 @@
       }
   
       bb8: {
+          Deinit(_0);                      // scope 1 at $DIR/issue-75439.rs:12:9: 12:13
           discriminant(_0) = 0;            // scope 1 at $DIR/issue-75439.rs:12:9: 12:13
           goto -> bb9;                     // scope 1 at $DIR/issue-75439.rs:9:5: 13:6
       }
diff --git a/src/test/mir-opt/lower_intrinsics.rs b/src/test/mir-opt/lower_intrinsics.rs
index 8a8880dad02..eab51b65f1a 100644
--- a/src/test/mir-opt/lower_intrinsics.rs
+++ b/src/test/mir-opt/lower_intrinsics.rs
@@ -3,7 +3,7 @@
 #![crate_type = "lib"]
 
 // EMIT_MIR lower_intrinsics.wrapping.LowerIntrinsics.diff
-pub fn wrapping<T: Copy>(a: T, b: T) {
+pub fn wrapping(a: i32, b: i32) {
     let _x = core::intrinsics::wrapping_add(a, b);
     let _y = core::intrinsics::wrapping_sub(a, b);
     let _z = core::intrinsics::wrapping_mul(a, b);
diff --git a/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff
index a531a19bd78..5a0286bad2f 100644
--- a/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff
@@ -1,23 +1,23 @@
 - // MIR for `wrapping` before LowerIntrinsics
 + // MIR for `wrapping` after LowerIntrinsics
   
-  fn wrapping(_1: T, _2: T) -> () {
-      debug a => _1;                       // in scope 0 at $DIR/lower_intrinsics.rs:6:26: 6:27
-      debug b => _2;                       // in scope 0 at $DIR/lower_intrinsics.rs:6:32: 6:33
-      let mut _0: ();                      // return place in scope 0 at $DIR/lower_intrinsics.rs:6:38: 6:38
-      let _3: T;                           // in scope 0 at $DIR/lower_intrinsics.rs:7:9: 7:11
-      let mut _4: T;                       // in scope 0 at $DIR/lower_intrinsics.rs:7:45: 7:46
-      let mut _5: T;                       // in scope 0 at $DIR/lower_intrinsics.rs:7:48: 7:49
-      let mut _7: T;                       // in scope 0 at $DIR/lower_intrinsics.rs:8:45: 8:46
-      let mut _8: T;                       // in scope 0 at $DIR/lower_intrinsics.rs:8:48: 8:49
-      let mut _10: T;                      // in scope 0 at $DIR/lower_intrinsics.rs:9:45: 9:46
-      let mut _11: T;                      // in scope 0 at $DIR/lower_intrinsics.rs:9:48: 9:49
+  fn wrapping(_1: i32, _2: i32) -> () {
+      debug a => _1;                       // in scope 0 at $DIR/lower_intrinsics.rs:6:17: 6:18
+      debug b => _2;                       // in scope 0 at $DIR/lower_intrinsics.rs:6:25: 6:26
+      let mut _0: ();                      // return place in scope 0 at $DIR/lower_intrinsics.rs:6:33: 6:33
+      let _3: i32;                         // in scope 0 at $DIR/lower_intrinsics.rs:7:9: 7:11
+      let mut _4: i32;                     // in scope 0 at $DIR/lower_intrinsics.rs:7:45: 7:46
+      let mut _5: i32;                     // in scope 0 at $DIR/lower_intrinsics.rs:7:48: 7:49
+      let mut _7: i32;                     // in scope 0 at $DIR/lower_intrinsics.rs:8:45: 8:46
+      let mut _8: i32;                     // in scope 0 at $DIR/lower_intrinsics.rs:8:48: 8:49
+      let mut _10: i32;                    // in scope 0 at $DIR/lower_intrinsics.rs:9:45: 9:46
+      let mut _11: i32;                    // in scope 0 at $DIR/lower_intrinsics.rs:9:48: 9:49
       scope 1 {
           debug _x => _3;                  // in scope 1 at $DIR/lower_intrinsics.rs:7:9: 7:11
-          let _6: T;                       // in scope 1 at $DIR/lower_intrinsics.rs:8:9: 8:11
+          let _6: i32;                     // in scope 1 at $DIR/lower_intrinsics.rs:8:9: 8:11
           scope 2 {
               debug _y => _6;              // in scope 2 at $DIR/lower_intrinsics.rs:8:9: 8:11
-              let _9: T;                   // in scope 2 at $DIR/lower_intrinsics.rs:9:9: 9:11
+              let _9: i32;                 // in scope 2 at $DIR/lower_intrinsics.rs:9:9: 9:11
               scope 3 {
                   debug _z => _9;          // in scope 3 at $DIR/lower_intrinsics.rs:9:9: 9:11
               }
@@ -30,10 +30,10 @@
           _4 = _1;                         // scope 0 at $DIR/lower_intrinsics.rs:7:45: 7:46
           StorageLive(_5);                 // scope 0 at $DIR/lower_intrinsics.rs:7:48: 7:49
           _5 = _2;                         // scope 0 at $DIR/lower_intrinsics.rs:7:48: 7:49
--         _3 = wrapping_add::<T>(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:7:14: 7:50
+-         _3 = wrapping_add::<i32>(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:7:14: 7:50
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:7:14: 7:44
--                                          // + literal: Const { ty: extern "rust-intrinsic" fn(T, T) -> T {wrapping_add::<T>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_add::<i32>}, val: Value(Scalar(<ZST>)) }
 +         _3 = Add(move _4, move _5);      // scope 0 at $DIR/lower_intrinsics.rs:7:14: 7:50
 +         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:7:14: 7:50
       }
@@ -46,10 +46,10 @@
           _7 = _1;                         // scope 1 at $DIR/lower_intrinsics.rs:8:45: 8:46
           StorageLive(_8);                 // scope 1 at $DIR/lower_intrinsics.rs:8:48: 8:49
           _8 = _2;                         // scope 1 at $DIR/lower_intrinsics.rs:8:48: 8:49
--         _6 = wrapping_sub::<T>(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:8:14: 8:50
+-         _6 = wrapping_sub::<i32>(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:8:14: 8:50
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:8:14: 8:44
--                                          // + literal: Const { ty: extern "rust-intrinsic" fn(T, T) -> T {wrapping_sub::<T>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_sub::<i32>}, val: Value(Scalar(<ZST>)) }
 +         _6 = Sub(move _7, move _8);      // scope 1 at $DIR/lower_intrinsics.rs:8:14: 8:50
 +         goto -> bb2;                     // scope 1 at $DIR/lower_intrinsics.rs:8:14: 8:50
       }
@@ -62,10 +62,10 @@
           _10 = _1;                        // scope 2 at $DIR/lower_intrinsics.rs:9:45: 9:46
           StorageLive(_11);                // scope 2 at $DIR/lower_intrinsics.rs:9:48: 9:49
           _11 = _2;                        // scope 2 at $DIR/lower_intrinsics.rs:9:48: 9:49
--         _9 = wrapping_mul::<T>(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:9:14: 9:50
+-         _9 = wrapping_mul::<i32>(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:9:14: 9:50
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:9:14: 9:44
--                                          // + literal: Const { ty: extern "rust-intrinsic" fn(T, T) -> T {wrapping_mul::<T>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_mul::<i32>}, val: Value(Scalar(<ZST>)) }
 +         _9 = Mul(move _10, move _11);    // scope 2 at $DIR/lower_intrinsics.rs:9:14: 9:50
 +         goto -> bb3;                     // scope 2 at $DIR/lower_intrinsics.rs:9:14: 9:50
       }
@@ -73,7 +73,7 @@
       bb3: {
           StorageDead(_11);                // scope 2 at $DIR/lower_intrinsics.rs:9:49: 9:50
           StorageDead(_10);                // scope 2 at $DIR/lower_intrinsics.rs:9:49: 9:50
-          _0 = const ();                   // scope 0 at $DIR/lower_intrinsics.rs:6:38: 10:2
+          _0 = const ();                   // scope 0 at $DIR/lower_intrinsics.rs:6:33: 10:2
           StorageDead(_9);                 // scope 2 at $DIR/lower_intrinsics.rs:10:1: 10:2
           StorageDead(_6);                 // scope 1 at $DIR/lower_intrinsics.rs:10:1: 10:2
           StorageDead(_3);                 // scope 0 at $DIR/lower_intrinsics.rs:10:1: 10:2
diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff
index d164f62c580..e63148a8312 100644
--- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff
@@ -41,6 +41,7 @@
 -         _3 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:22
 -         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:30:13: 30:22
 -         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:31:13: 31:21
+-         nop;                             // scope 4 at $DIR/matches_reduce_branches.rs:32:13: 32:15
 -         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:32:13: 32:15
 -     }
 - 
@@ -53,6 +54,7 @@
 +         _3 = Eq(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21
           _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:22
           _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:24:13: 24:21
+-         nop;                             // scope 4 at $DIR/matches_reduce_branches.rs:25:13: 25:15
 -         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:25:13: 25:15
 -     }
 - 
@@ -67,6 +69,7 @@
           _9 = _4;                         // scope 4 at $DIR/matches_reduce_branches.rs:36:12: 36:13
           StorageLive(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:36:15: 36:16
           _10 = _5;                        // scope 4 at $DIR/matches_reduce_branches.rs:36:15: 36:16
+          Deinit(_0);                      // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17
           (_0.0: bool) = move _7;          // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17
           (_0.1: bool) = move _8;          // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17
           (_0.2: bool) = move _9;          // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17
diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff
index d164f62c580..e63148a8312 100644
--- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff
+++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff
@@ -41,6 +41,7 @@
 -         _3 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:22
 -         _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:30:13: 30:22
 -         _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:31:13: 31:21
+-         nop;                             // scope 4 at $DIR/matches_reduce_branches.rs:32:13: 32:15
 -         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:32:13: 32:15
 -     }
 - 
@@ -53,6 +54,7 @@
 +         _3 = Eq(_11, const 7_i32);       // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21
           _4 = const false;                // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:22
           _5 = const true;                 // scope 4 at $DIR/matches_reduce_branches.rs:24:13: 24:21
+-         nop;                             // scope 4 at $DIR/matches_reduce_branches.rs:25:13: 25:15
 -         goto -> bb3;                     // scope 4 at $DIR/matches_reduce_branches.rs:25:13: 25:15
 -     }
 - 
@@ -67,6 +69,7 @@
           _9 = _4;                         // scope 4 at $DIR/matches_reduce_branches.rs:36:12: 36:13
           StorageLive(_10);                // scope 4 at $DIR/matches_reduce_branches.rs:36:15: 36:16
           _10 = _5;                        // scope 4 at $DIR/matches_reduce_branches.rs:36:15: 36:16
+          Deinit(_0);                      // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17
           (_0.0: bool) = move _7;          // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17
           (_0.1: bool) = move _8;          // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17
           (_0.2: bool) = move _9;          // scope 4 at $DIR/matches_reduce_branches.rs:36:5: 36:17
diff --git a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
index 312031b7a0f..5131e2f088d 100644
--- a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
+++ b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
@@ -38,6 +38,7 @@
           _1 = const 0_i32;                // scope 0 at $DIR/remove_storage_markers.rs:7:19: 7:20
 -         StorageLive(_2);                 // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19
 -         StorageLive(_3);                 // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19
+          Deinit(_3);                      // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19
           (_3.0: i32) = const 0_i32;       // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19
           (_3.1: i32) = const 10_i32;      // scope 1 at $DIR/remove_storage_markers.rs:8:14: 8:19
           _2 = move _3;                    // scope 4 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
diff --git a/src/test/mir-opt/remove_zsts_dont_touch_unions.get_union.RemoveZsts.after.mir b/src/test/mir-opt/remove_zsts_dont_touch_unions.get_union.RemoveZsts.after.mir
index 33bd9eb9b19..ad8f0acc763 100644
--- a/src/test/mir-opt/remove_zsts_dont_touch_unions.get_union.RemoveZsts.after.mir
+++ b/src/test/mir-opt/remove_zsts_dont_touch_unions.get_union.RemoveZsts.after.mir
@@ -6,6 +6,8 @@ fn get_union() -> Foo {
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:13:14: 13:16
+        nop;                             // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:13:14: 13:16
+        Deinit(_0);                      // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:13:5: 13:18
         (_0.0: ()) = move _1;            // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:13:5: 13:18
         StorageDead(_1);                 // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:13:17: 13:18
         return;                          // scope 0 at $DIR/remove_zsts_dont_touch_unions.rs:14:2: 14:2
diff --git a/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff b/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff
index 45a7fac6315..4cdbaec7d2a 100644
--- a/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff
+++ b/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff
@@ -65,6 +65,7 @@
           _9 = ((_3 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
           _2 = _9;                         // scope 4 at $DIR/separate_const_switch.rs:29:8: 29:10
           StorageDead(_9);                 // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+          Deinit(_0);                      // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11
           ((_0 as Ok).0: i32) = move _2;   // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11
           discriminant(_0) = 0;            // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11
           StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:29:10: 29:11
@@ -84,6 +85,7 @@
           _18 = move _16;                  // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           _17 = move _18;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
           StorageDead(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
@@ -101,9 +103,11 @@
           StorageLive(_14);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageLive(_15);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           _15 = move _13;                  // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+          Deinit(_14);                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           ((_14 as Err).0: i32) = move _15; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           discriminant(_14) = 1;           // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_15);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+          Deinit(_3);                      // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>) = move _14; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           discriminant(_3) = 1;            // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_14);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
@@ -125,6 +129,7 @@
           _11 = move ((_4 as Ok).0: i32);  // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageLive(_12);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
           _12 = move _11;                  // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
+          Deinit(_3);                      // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
           ((_3 as Continue).0: i32) = move _12; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
           discriminant(_3) = 0;            // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_12);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
diff --git a/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir b/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir
index 1476f06f25b..f4c526c6b19 100644
--- a/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir
+++ b/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir
@@ -63,9 +63,11 @@ fn identity(_1: Result<i32, i32>) -> Result<i32, i32> {
         StorageLive(_12);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
         StorageLive(_13);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
         _13 = move _11;                  // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+        Deinit(_12);                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
         ((_12 as Err).0: i32) = move _13; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
         discriminant(_12) = 1;           // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
         StorageDead(_13);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+        Deinit(_3);                      // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
         ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>) = move _12; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
         discriminant(_3) = 1;            // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
         StorageDead(_12);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
@@ -83,6 +85,7 @@ fn identity(_1: Result<i32, i32>) -> Result<i32, i32> {
         _16 = move _14;                  // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
         _15 = move _16;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
         StorageDead(_16);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+        Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
         ((_0 as Err).0: i32) = move _15; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
         discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
         StorageDead(_15);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
@@ -103,6 +106,7 @@ fn identity(_1: Result<i32, i32>) -> Result<i32, i32> {
         _9 = move ((_4 as Ok).0: i32);   // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
         StorageLive(_10);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
         _10 = move _9;                   // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
+        Deinit(_3);                      // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
         ((_3 as Continue).0: i32) = move _10; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
         discriminant(_3) = 0;            // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
         StorageDead(_10);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
@@ -113,6 +117,7 @@ fn identity(_1: Result<i32, i32>) -> Result<i32, i32> {
         _7 = ((_3 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
         _2 = _7;                         // scope 4 at $DIR/separate_const_switch.rs:29:8: 29:10
         StorageDead(_7);                 // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+        Deinit(_0);                      // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11
         ((_0 as Ok).0: i32) = move _2;   // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11
         discriminant(_0) = 0;            // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11
         StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:29:10: 29:11
diff --git a/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff b/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
index da0ea8a585c..d94967072ba 100644
--- a/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
+++ b/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
@@ -73,6 +73,7 @@
           _9 = ((_3 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:29:8: 29:10
           _2 = _9;                         // scope 4 at $DIR/separate_const_switch.rs:29:8: 29:10
           StorageDead(_9);                 // scope 0 at $DIR/separate_const_switch.rs:29:9: 29:10
+          Deinit(_0);                      // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11
           ((_0 as Ok).0: i32) = move _2;   // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11
           discriminant(_0) = 0;            // scope 0 at $DIR/separate_const_switch.rs:29:5: 29:11
           StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:29:10: 29:11
@@ -93,6 +94,7 @@
           _18 = move _16;                  // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           _17 = move _18;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
           StorageDead(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
+          Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
@@ -111,9 +113,11 @@
           StorageLive(_14);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageLive(_15);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           _15 = move _13;                  // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+          Deinit(_14);                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           ((_14 as Err).0: i32) = move _15; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           discriminant(_14) = 1;           // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_15);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
+          Deinit(_3);                      // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           ((_3 as Break).0: std::result::Result<std::convert::Infallible, i32>) = move _14; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           discriminant(_3) = 1;            // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_14);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
@@ -136,6 +140,7 @@
           _11 = move ((_4 as Ok).0: i32);  // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageLive(_12);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
           _12 = move _11;                  // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
+          Deinit(_3);                      // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
           ((_3 as Continue).0: i32) = move _12; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
           discriminant(_3) = 0;            // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
           StorageDead(_12);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
diff --git a/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff b/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff
index 5316c34fb37..ea549a76f58 100644
--- a/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff
+++ b/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff
@@ -38,6 +38,7 @@
           _6 = ((_1 as Err).0: usize);     // scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18
           StorageLive(_7);                 // scope 2 at $DIR/separate_const_switch.rs:17:42: 17:43
           _7 = _6;                         // scope 2 at $DIR/separate_const_switch.rs:17:42: 17:43
+          Deinit(_2);                      // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44
           ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44
           discriminant(_2) = 1;            // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44
           StorageDead(_7);                 // scope 2 at $DIR/separate_const_switch.rs:17:43: 17:44
@@ -53,6 +54,7 @@
           _4 = ((_1 as Ok).0: i32);        // scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17
           StorageLive(_5);                 // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45
           _5 = _4;                         // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45
+          Deinit(_2);                      // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46
           ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46
           discriminant(_2) = 0;            // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46
           StorageDead(_5);                 // scope 1 at $DIR/separate_const_switch.rs:16:45: 16:46
@@ -66,6 +68,7 @@
       bb3: {
           StorageLive(_11);                // scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29
           _11 = ((_2 as Break).0: usize);  // scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29
+          Deinit(_0);                      // scope 4 at $DIR/separate_const_switch.rs:21:34: 21:38
           discriminant(_0) = 0;            // scope 4 at $DIR/separate_const_switch.rs:21:34: 21:38
           StorageDead(_11);                // scope 0 at $DIR/separate_const_switch.rs:21:37: 21:38
           goto -> bb5;                     // scope 0 at $DIR/separate_const_switch.rs:21:37: 21:38
@@ -76,6 +79,7 @@
           _9 = ((_2 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32
           StorageLive(_10);                // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43
           _10 = _9;                        // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43
+          Deinit(_0);                      // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44
           ((_0 as Some).0: i32) = move _10; // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44
           discriminant(_0) = 1;            // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44
           StorageDead(_10);                // scope 3 at $DIR/separate_const_switch.rs:20:43: 20:44
diff --git a/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir b/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir
index 38ad12157e2..d388376ca48 100644
--- a/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir
+++ b/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir
@@ -36,12 +36,14 @@ fn too_complex(_1: Result<i32, usize>) -> Option<i32> {
         _6 = ((_1 as Err).0: usize);     // scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18
         StorageLive(_7);                 // scope 2 at $DIR/separate_const_switch.rs:17:42: 17:43
         _7 = _6;                         // scope 2 at $DIR/separate_const_switch.rs:17:42: 17:43
+        Deinit(_2);                      // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44
         ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44
         discriminant(_2) = 1;            // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44
         StorageDead(_7);                 // scope 2 at $DIR/separate_const_switch.rs:17:43: 17:44
         StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:17:43: 17:44
         StorageLive(_10);                // scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29
         _10 = ((_2 as Break).0: usize);  // scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29
+        Deinit(_0);                      // scope 4 at $DIR/separate_const_switch.rs:21:34: 21:38
         discriminant(_0) = 0;            // scope 4 at $DIR/separate_const_switch.rs:21:34: 21:38
         StorageDead(_10);                // scope 0 at $DIR/separate_const_switch.rs:21:37: 21:38
         goto -> bb3;                     // scope 0 at $DIR/separate_const_switch.rs:21:37: 21:38
@@ -52,6 +54,7 @@ fn too_complex(_1: Result<i32, usize>) -> Option<i32> {
         _4 = ((_1 as Ok).0: i32);        // scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17
         StorageLive(_5);                 // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45
         _5 = _4;                         // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45
+        Deinit(_2);                      // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46
         ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46
         discriminant(_2) = 0;            // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46
         StorageDead(_5);                 // scope 1 at $DIR/separate_const_switch.rs:16:45: 16:46
@@ -60,6 +63,7 @@ fn too_complex(_1: Result<i32, usize>) -> Option<i32> {
         _8 = ((_2 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32
         StorageLive(_9);                 // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43
         _9 = _8;                         // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43
+        Deinit(_0);                      // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44
         ((_0 as Some).0: i32) = move _9; // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44
         discriminant(_0) = 1;            // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44
         StorageDead(_9);                 // scope 3 at $DIR/separate_const_switch.rs:20:43: 20:44
diff --git a/src/test/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff b/src/test/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff
index 0b5b9a490c6..11f8d509281 100644
--- a/src/test/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff
+++ b/src/test/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff
@@ -38,6 +38,7 @@
           _6 = ((_1 as Err).0: usize);     // scope 0 at $DIR/separate_const_switch.rs:17:17: 17:18
           StorageLive(_7);                 // scope 2 at $DIR/separate_const_switch.rs:17:42: 17:43
           _7 = _6;                         // scope 2 at $DIR/separate_const_switch.rs:17:42: 17:43
+          Deinit(_2);                      // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44
           ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44
           discriminant(_2) = 1;            // scope 2 at $DIR/separate_const_switch.rs:17:23: 17:44
           StorageDead(_7);                 // scope 2 at $DIR/separate_const_switch.rs:17:43: 17:44
@@ -52,6 +53,7 @@
           _4 = ((_1 as Ok).0: i32);        // scope 0 at $DIR/separate_const_switch.rs:16:16: 16:17
           StorageLive(_5);                 // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45
           _5 = _4;                         // scope 1 at $DIR/separate_const_switch.rs:16:44: 16:45
+          Deinit(_2);                      // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46
           ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46
           discriminant(_2) = 0;            // scope 1 at $DIR/separate_const_switch.rs:16:22: 16:46
           StorageDead(_5);                 // scope 1 at $DIR/separate_const_switch.rs:16:45: 16:46
@@ -69,6 +71,7 @@
 +     bb3: {
           StorageLive(_11);                // scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29
           _11 = ((_2 as Break).0: usize);  // scope 0 at $DIR/separate_const_switch.rs:21:28: 21:29
+          Deinit(_0);                      // scope 4 at $DIR/separate_const_switch.rs:21:34: 21:38
           discriminant(_0) = 0;            // scope 4 at $DIR/separate_const_switch.rs:21:34: 21:38
           StorageDead(_11);                // scope 0 at $DIR/separate_const_switch.rs:21:37: 21:38
 -         goto -> bb6;                     // scope 0 at $DIR/separate_const_switch.rs:21:37: 21:38
@@ -81,6 +84,7 @@
           _9 = ((_2 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:20:31: 20:32
           StorageLive(_10);                // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43
           _10 = _9;                        // scope 3 at $DIR/separate_const_switch.rs:20:42: 20:43
+          Deinit(_0);                      // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44
           ((_0 as Some).0: i32) = move _10; // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44
           discriminant(_0) = 1;            // scope 3 at $DIR/separate_const_switch.rs:20:37: 20:44
           StorageDead(_10);                // scope 3 at $DIR/separate_const_switch.rs:20:43: 20:44
diff --git a/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff
index ad47891294a..389dbd27b5d 100644
--- a/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff
+++ b/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff
@@ -8,8 +8,7 @@
       let _3: u8;                          // in scope 0 at $DIR/simplify-arm.rs:11:14: 11:15
       let mut _4: u8;                      // in scope 0 at $DIR/simplify-arm.rs:11:25: 11:26
       scope 1 {
--         debug v => _3;                   // in scope 1 at $DIR/simplify-arm.rs:11:14: 11:15
-+         debug v => ((_0 as Some).0: u8); // in scope 1 at $DIR/simplify-arm.rs:11:14: 11:15
+          debug v => _3;                   // in scope 1 at $DIR/simplify-arm.rs:11:14: 11:15
       }
   
       bb0: {
@@ -18,6 +17,7 @@
       }
   
       bb1: {
+          Deinit(_0);                      // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21
           discriminant(_0) = 0;            // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21
           goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21
       }
@@ -27,15 +27,15 @@
       }
   
       bb3: {
--         StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15
--         _3 = ((_1 as Some).0: u8);       // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15
--         StorageLive(_4);                 // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26
--         _4 = _3;                         // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26
--         ((_0 as Some).0: u8) = move _4;  // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
--         discriminant(_0) = 1;            // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
--         StorageDead(_4);                 // scope 1 at $DIR/simplify-arm.rs:11:26: 11:27
--         StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:11:26: 11:27
-+         _0 = move _1;                    // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
+          StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15
+          _3 = ((_1 as Some).0: u8);       // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15
+          StorageLive(_4);                 // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26
+          _4 = _3;                         // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26
+          Deinit(_0);                      // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
+          ((_0 as Some).0: u8) = move _4;  // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
+          discriminant(_0) = 1;            // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
+          StorageDead(_4);                 // scope 1 at $DIR/simplify-arm.rs:11:26: 11:27
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:11:26: 11:27
           goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:11:26: 11:27
       }
   
diff --git a/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff
index 52c036a7700..32b7b9aa555 100644
--- a/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff
+++ b/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff
@@ -8,32 +8,38 @@
       let _3: u8;                          // in scope 0 at $DIR/simplify-arm.rs:11:14: 11:15
       let mut _4: u8;                      // in scope 0 at $DIR/simplify-arm.rs:11:25: 11:26
       scope 1 {
-          debug v => ((_0 as Some).0: u8); // in scope 1 at $DIR/simplify-arm.rs:11:14: 11:15
+          debug v => _3;                   // in scope 1 at $DIR/simplify-arm.rs:11:14: 11:15
       }
   
       bb0: {
           _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12
--         switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:10:5: 10:12
-+         goto -> bb1;                     // scope 0 at $DIR/simplify-arm.rs:10:5: 10:12
+          switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:10:5: 10:12
       }
   
       bb1: {
--         discriminant(_0) = 0;            // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21
--         goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21
--     }
-- 
--     bb2: {
--         unreachable;                     // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12
--     }
-- 
--     bb3: {
-          _0 = move _1;                    // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
--         goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:11:26: 11:27
-+         goto -> bb2;                     // scope 0 at $DIR/simplify-arm.rs:11:26: 11:27
+          Deinit(_0);                      // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21
+          discriminant(_0) = 0;            // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21
       }
   
--     bb4: {
-+     bb2: {
+      bb2: {
+          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12
+      }
+  
+      bb3: {
+          StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15
+          _3 = ((_1 as Some).0: u8);       // scope 0 at $DIR/simplify-arm.rs:11:14: 11:15
+          StorageLive(_4);                 // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26
+          _4 = _3;                         // scope 1 at $DIR/simplify-arm.rs:11:25: 11:26
+          Deinit(_0);                      // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
+          ((_0 as Some).0: u8) = move _4;  // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
+          discriminant(_0) = 1;            // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27
+          StorageDead(_4);                 // scope 1 at $DIR/simplify-arm.rs:11:26: 11:27
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:11:26: 11:27
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:11:26: 11:27
+      }
+  
+      bb4: {
           return;                          // scope 0 at $DIR/simplify-arm.rs:14:2: 14:2
       }
   }
diff --git a/src/test/mir-opt/simplify_arm.id_result.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_arm.id_result.SimplifyArmIdentity.diff
index b24bdea9b71..60d421a2e1a 100644
--- a/src/test/mir-opt/simplify_arm.id_result.SimplifyArmIdentity.diff
+++ b/src/test/mir-opt/simplify_arm.id_result.SimplifyArmIdentity.diff
@@ -10,12 +10,10 @@
       let _5: i32;                         // in scope 0 at $DIR/simplify-arm.rs:19:13: 19:14
       let mut _6: i32;                     // in scope 0 at $DIR/simplify-arm.rs:19:23: 19:24
       scope 1 {
--         debug x => _3;                   // in scope 1 at $DIR/simplify-arm.rs:18:12: 18:13
-+         debug x => ((_0 as Ok).0: u8);   // in scope 1 at $DIR/simplify-arm.rs:18:12: 18:13
+          debug x => _3;                   // in scope 1 at $DIR/simplify-arm.rs:18:12: 18:13
       }
       scope 2 {
--         debug y => _5;                   // in scope 2 at $DIR/simplify-arm.rs:19:13: 19:14
-+         debug y => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:19:13: 19:14
+          debug y => _5;                   // in scope 2 at $DIR/simplify-arm.rs:19:13: 19:14
       }
   
       bb0: {
@@ -24,15 +22,15 @@
       }
   
       bb1: {
--         StorageLive(_5);                 // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14
--         _5 = ((_1 as Err).0: i32);       // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14
--         StorageLive(_6);                 // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24
--         _6 = _5;                         // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24
--         ((_0 as Err).0: i32) = move _6;  // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
--         discriminant(_0) = 1;            // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
--         StorageDead(_6);                 // scope 2 at $DIR/simplify-arm.rs:19:24: 19:25
--         StorageDead(_5);                 // scope 0 at $DIR/simplify-arm.rs:19:24: 19:25
-+         _0 = move _1;                    // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
+          StorageLive(_5);                 // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14
+          _5 = ((_1 as Err).0: i32);       // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14
+          StorageLive(_6);                 // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24
+          _6 = _5;                         // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24
+          Deinit(_0);                      // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
+          ((_0 as Err).0: i32) = move _6;  // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
+          discriminant(_0) = 1;            // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
+          StorageDead(_6);                 // scope 2 at $DIR/simplify-arm.rs:19:24: 19:25
+          StorageDead(_5);                 // scope 0 at $DIR/simplify-arm.rs:19:24: 19:25
           goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:19:24: 19:25
       }
   
@@ -41,15 +39,15 @@
       }
   
       bb3: {
--         StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13
--         _3 = ((_1 as Ok).0: u8);         // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13
--         StorageLive(_4);                 // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22
--         _4 = _3;                         // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22
--         ((_0 as Ok).0: u8) = move _4;    // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
--         discriminant(_0) = 0;            // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
--         StorageDead(_4);                 // scope 1 at $DIR/simplify-arm.rs:18:22: 18:23
--         StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:18:22: 18:23
-+         _0 = move _1;                    // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
+          StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13
+          _3 = ((_1 as Ok).0: u8);         // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13
+          StorageLive(_4);                 // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22
+          _4 = _3;                         // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22
+          Deinit(_0);                      // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
+          ((_0 as Ok).0: u8) = move _4;    // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
+          discriminant(_0) = 0;            // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
+          StorageDead(_4);                 // scope 1 at $DIR/simplify-arm.rs:18:22: 18:23
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:18:22: 18:23
           goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:18:22: 18:23
       }
   
diff --git a/src/test/mir-opt/simplify_arm.id_result.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id_result.SimplifyBranchSame.diff
index 4d6a4edb08a..52adf11d0f5 100644
--- a/src/test/mir-opt/simplify_arm.id_result.SimplifyBranchSame.diff
+++ b/src/test/mir-opt/simplify_arm.id_result.SimplifyBranchSame.diff
@@ -10,35 +10,48 @@
       let _5: i32;                         // in scope 0 at $DIR/simplify-arm.rs:19:13: 19:14
       let mut _6: i32;                     // in scope 0 at $DIR/simplify-arm.rs:19:23: 19:24
       scope 1 {
-          debug x => ((_0 as Ok).0: u8);   // in scope 1 at $DIR/simplify-arm.rs:18:12: 18:13
+          debug x => _3;                   // in scope 1 at $DIR/simplify-arm.rs:18:12: 18:13
       }
       scope 2 {
-          debug y => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:19:13: 19:14
+          debug y => _5;                   // in scope 2 at $DIR/simplify-arm.rs:19:13: 19:14
       }
   
       bb0: {
           _2 = discriminant(_1);           // scope 0 at $DIR/simplify-arm.rs:17:11: 17:12
--         switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:17:5: 17:12
-+         goto -> bb1;                     // scope 0 at $DIR/simplify-arm.rs:17:5: 17:12
+          switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:17:5: 17:12
       }
   
       bb1: {
--         _0 = move _1;                    // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
--         goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:19:24: 19:25
--     }
-- 
--     bb2: {
--         unreachable;                     // scope 0 at $DIR/simplify-arm.rs:17:11: 17:12
--     }
-- 
--     bb3: {
-          _0 = move _1;                    // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
--         goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:18:22: 18:23
-+         goto -> bb2;                     // scope 0 at $DIR/simplify-arm.rs:18:22: 18:23
+          StorageLive(_5);                 // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14
+          _5 = ((_1 as Err).0: i32);       // scope 0 at $DIR/simplify-arm.rs:19:13: 19:14
+          StorageLive(_6);                 // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24
+          _6 = _5;                         // scope 2 at $DIR/simplify-arm.rs:19:23: 19:24
+          Deinit(_0);                      // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
+          ((_0 as Err).0: i32) = move _6;  // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
+          discriminant(_0) = 1;            // scope 2 at $DIR/simplify-arm.rs:19:19: 19:25
+          StorageDead(_6);                 // scope 2 at $DIR/simplify-arm.rs:19:24: 19:25
+          StorageDead(_5);                 // scope 0 at $DIR/simplify-arm.rs:19:24: 19:25
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:19:24: 19:25
       }
   
--     bb4: {
-+     bb2: {
+      bb2: {
+          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:17:11: 17:12
+      }
+  
+      bb3: {
+          StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13
+          _3 = ((_1 as Ok).0: u8);         // scope 0 at $DIR/simplify-arm.rs:18:12: 18:13
+          StorageLive(_4);                 // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22
+          _4 = _3;                         // scope 1 at $DIR/simplify-arm.rs:18:21: 18:22
+          Deinit(_0);                      // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
+          ((_0 as Ok).0: u8) = move _4;    // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
+          discriminant(_0) = 0;            // scope 1 at $DIR/simplify-arm.rs:18:18: 18:23
+          StorageDead(_4);                 // scope 1 at $DIR/simplify-arm.rs:18:22: 18:23
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:18:22: 18:23
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:18:22: 18:23
+      }
+  
+      bb4: {
           return;                          // scope 0 at $DIR/simplify-arm.rs:21:2: 21:2
       }
   }
diff --git a/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff
index 7cd095c2db1..5da2ad1a27d 100644
--- a/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff
+++ b/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff
@@ -15,24 +15,19 @@
       let _10: u8;                         // in scope 0 at $DIR/simplify-arm.rs:38:12: 38:13
       let mut _11: u8;                     // in scope 0 at $DIR/simplify-arm.rs:40:8: 40:9
       scope 1 {
--         debug x => _2;                   // in scope 1 at $DIR/simplify-arm.rs:36:9: 36:10
-+         debug x => ((_0 as Ok).0: u8);   // in scope 1 at $DIR/simplify-arm.rs:36:9: 36:10
+          debug x => _2;                   // in scope 1 at $DIR/simplify-arm.rs:36:9: 36:10
       }
       scope 2 {
--         debug e => _6;                   // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14
-+         debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14
+          debug e => _6;                   // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14
           scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify-arm.rs:37:37: 37:50
--             debug t => _9;               // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-+             debug t => ((_0 as Err).0: i32); // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+              debug t => _9;               // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
           }
           scope 6 (inlined from_error::<u8, i32>) { // at $DIR/simplify-arm.rs:37:26: 37:51
--             debug e => _8;               // in scope 6 at $DIR/simplify-arm.rs:27:21: 27:22
-+             debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify-arm.rs:27:21: 27:22
+              debug e => _8;               // in scope 6 at $DIR/simplify-arm.rs:27:21: 27:22
           }
       }
       scope 3 {
--         debug v => _10;                  // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13
-+         debug v => ((_0 as Ok).0: u8);   // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13
+          debug v => _10;                  // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13
       }
       scope 4 (inlined into_result::<u8, i32>) { // at $DIR/simplify-arm.rs:36:19: 36:33
           debug r => _4;                   // in scope 4 at $DIR/simplify-arm.rs:23:22: 23:23
@@ -50,17 +45,17 @@
       }
   
       bb1: {
--         StorageLive(_10);                // scope 0 at $DIR/simplify-arm.rs:38:12: 38:13
--         _10 = ((_3 as Ok).0: u8);        // scope 0 at $DIR/simplify-arm.rs:38:12: 38:13
--         _2 = _10;                        // scope 3 at $DIR/simplify-arm.rs:38:18: 38:19
--         StorageDead(_10);                // scope 0 at $DIR/simplify-arm.rs:38:18: 38:19
-+         _0 = move _3;                    // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10
+          StorageLive(_10);                // scope 0 at $DIR/simplify-arm.rs:38:12: 38:13
+          _10 = ((_3 as Ok).0: u8);        // scope 0 at $DIR/simplify-arm.rs:38:12: 38:13
+          _2 = _10;                        // scope 3 at $DIR/simplify-arm.rs:38:18: 38:19
+          StorageDead(_10);                // scope 0 at $DIR/simplify-arm.rs:38:18: 38:19
           StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7
--         StorageLive(_11);                // scope 1 at $DIR/simplify-arm.rs:40:8: 40:9
--         _11 = _2;                        // scope 1 at $DIR/simplify-arm.rs:40:8: 40:9
--         ((_0 as Ok).0: u8) = move _11;   // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10
--         discriminant(_0) = 0;            // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10
--         StorageDead(_11);                // scope 1 at $DIR/simplify-arm.rs:40:9: 40:10
+          StorageLive(_11);                // scope 1 at $DIR/simplify-arm.rs:40:8: 40:9
+          _11 = _2;                        // scope 1 at $DIR/simplify-arm.rs:40:8: 40:9
+          Deinit(_0);                      // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10
+          ((_0 as Ok).0: u8) = move _11;   // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10
+          discriminant(_0) = 0;            // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10
+          StorageDead(_11);                // scope 1 at $DIR/simplify-arm.rs:40:9: 40:10
           StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2
           goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
       }
@@ -70,18 +65,18 @@
       }
   
       bb3: {
--         StorageLive(_6);                 // scope 0 at $DIR/simplify-arm.rs:37:13: 37:14
--         _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify-arm.rs:37:13: 37:14
--         StorageLive(_8);                 // scope 2 at $DIR/simplify-arm.rs:37:37: 37:50
--         StorageLive(_9);                 // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49
--         _9 = _6;                         // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49
--         _8 = move _9;                    // scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
--         StorageDead(_9);                 // scope 2 at $DIR/simplify-arm.rs:37:49: 37:50
--         ((_0 as Err).0: i32) = move _8;  // scope 6 at $DIR/simplify-arm.rs:28:9: 28:10
--         discriminant(_0) = 1;            // scope 6 at $DIR/simplify-arm.rs:28:5: 28:11
--         StorageDead(_8);                 // scope 2 at $DIR/simplify-arm.rs:37:50: 37:51
--         StorageDead(_6);                 // scope 0 at $DIR/simplify-arm.rs:37:50: 37:51
-+         _0 = move _3;                    // scope 6 at $DIR/simplify-arm.rs:28:5: 28:11
+          StorageLive(_6);                 // scope 0 at $DIR/simplify-arm.rs:37:13: 37:14
+          _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify-arm.rs:37:13: 37:14
+          StorageLive(_8);                 // scope 2 at $DIR/simplify-arm.rs:37:37: 37:50
+          StorageLive(_9);                 // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49
+          _9 = _6;                         // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49
+          _8 = move _9;                    // scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+          StorageDead(_9);                 // scope 2 at $DIR/simplify-arm.rs:37:49: 37:50
+          ((_0 as Err).0: i32) = move _8;  // scope 6 at $DIR/simplify-arm.rs:28:9: 28:10
+          Deinit(_0);                      // scope 6 at $DIR/simplify-arm.rs:28:5: 28:11
+          discriminant(_0) = 1;            // scope 6 at $DIR/simplify-arm.rs:28:5: 28:11
+          StorageDead(_8);                 // scope 2 at $DIR/simplify-arm.rs:37:50: 37:51
+          StorageDead(_6);                 // scope 0 at $DIR/simplify-arm.rs:37:50: 37:51
           StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7
           StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2
           goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
diff --git a/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff
index 91c5c630163..528828ad075 100644
--- a/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff
+++ b/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff
@@ -15,19 +15,19 @@
       let _10: u8;                         // in scope 0 at $DIR/simplify-arm.rs:38:12: 38:13
       let mut _11: u8;                     // in scope 0 at $DIR/simplify-arm.rs:40:8: 40:9
       scope 1 {
-          debug x => ((_0 as Ok).0: u8);   // in scope 1 at $DIR/simplify-arm.rs:36:9: 36:10
+          debug x => _2;                   // in scope 1 at $DIR/simplify-arm.rs:36:9: 36:10
       }
       scope 2 {
-          debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14
+          debug e => _6;                   // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14
           scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify-arm.rs:37:37: 37:50
-              debug t => ((_0 as Err).0: i32); // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+              debug t => _9;               // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
           }
           scope 6 (inlined from_error::<u8, i32>) { // at $DIR/simplify-arm.rs:37:26: 37:51
-              debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify-arm.rs:27:21: 27:22
+              debug e => _8;               // in scope 6 at $DIR/simplify-arm.rs:27:21: 27:22
           }
       }
       scope 3 {
-          debug v => ((_0 as Ok).0: u8);   // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13
+          debug v => _10;                  // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13
       }
       scope 4 (inlined into_result::<u8, i32>) { // at $DIR/simplify-arm.rs:36:19: 36:33
           debug r => _4;                   // in scope 4 at $DIR/simplify-arm.rs:23:22: 23:23
@@ -41,30 +41,48 @@
           _3 = move _4;                    // scope 4 at $DIR/simplify-arm.rs:24:5: 24:6
           StorageDead(_4);                 // scope 0 at $DIR/simplify-arm.rs:36:32: 36:33
           _5 = discriminant(_3);           // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33
--         switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:36:13: 36:33
-+         goto -> bb1;                     // scope 0 at $DIR/simplify-arm.rs:36:13: 36:33
+          switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:36:13: 36:33
       }
   
       bb1: {
-          _0 = move _3;                    // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10
+          StorageLive(_10);                // scope 0 at $DIR/simplify-arm.rs:38:12: 38:13
+          _10 = ((_3 as Ok).0: u8);        // scope 0 at $DIR/simplify-arm.rs:38:12: 38:13
+          _2 = _10;                        // scope 3 at $DIR/simplify-arm.rs:38:18: 38:19
+          StorageDead(_10);                // scope 0 at $DIR/simplify-arm.rs:38:18: 38:19
           StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7
+          StorageLive(_11);                // scope 1 at $DIR/simplify-arm.rs:40:8: 40:9
+          _11 = _2;                        // scope 1 at $DIR/simplify-arm.rs:40:8: 40:9
+          Deinit(_0);                      // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10
+          ((_0 as Ok).0: u8) = move _11;   // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10
+          discriminant(_0) = 0;            // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10
+          StorageDead(_11);                // scope 1 at $DIR/simplify-arm.rs:40:9: 40:10
           StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2
--         goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
-+         goto -> bb2;                     // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
       }
   
       bb2: {
--         unreachable;                     // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33
--     }
-- 
--     bb3: {
--         _0 = move _3;                    // scope 6 at $DIR/simplify-arm.rs:28:5: 28:11
--         StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7
--         StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2
--         goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
--     }
-- 
--     bb4: {
+          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33
+      }
+  
+      bb3: {
+          StorageLive(_6);                 // scope 0 at $DIR/simplify-arm.rs:37:13: 37:14
+          _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify-arm.rs:37:13: 37:14
+          StorageLive(_8);                 // scope 2 at $DIR/simplify-arm.rs:37:37: 37:50
+          StorageLive(_9);                 // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49
+          _9 = _6;                         // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49
+          _8 = move _9;                    // scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+          StorageDead(_9);                 // scope 2 at $DIR/simplify-arm.rs:37:49: 37:50
+          ((_0 as Err).0: i32) = move _8;  // scope 6 at $DIR/simplify-arm.rs:28:9: 28:10
+          Deinit(_0);                      // scope 6 at $DIR/simplify-arm.rs:28:5: 28:11
+          discriminant(_0) = 1;            // scope 6 at $DIR/simplify-arm.rs:28:5: 28:11
+          StorageDead(_8);                 // scope 2 at $DIR/simplify-arm.rs:37:50: 37:51
+          StorageDead(_6);                 // scope 0 at $DIR/simplify-arm.rs:37:50: 37:51
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7
+          StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
+      }
+  
+      bb4: {
           return;                          // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
       }
   }
diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff
index 512d9fe172b..474d2df7aad 100644
--- a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff
+++ b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff
@@ -19,6 +19,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
+          Deinit(_1);                      // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
           ((_1 as Foo).0: u8) = const 0_u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
           discriminant(_1) = 0;            // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
           StorageLive(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
@@ -27,6 +28,7 @@
       }
   
       bb1: {
+          Deinit(_2);                      // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
           ((_2 as Foo).0: u8) = const 0_u8; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
           discriminant(_2) = 0;            // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
           goto -> bb4;                     // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
@@ -41,6 +43,7 @@
           _4 = ((_1 as Foo).0: u8);        // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
           StorageLive(_5);                 // scope 3 at $DIR/simplify-arm-identity.rs:20:33: 20:34
           _5 = _4;                         // scope 3 at $DIR/simplify-arm-identity.rs:20:33: 20:34
+          Deinit(_2);                      // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
           ((_2 as Foo).0: u8) = move _5;   // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
           discriminant(_2) = 0;            // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
           StorageDead(_5);                 // scope 3 at $DIR/simplify-arm-identity.rs:20:34: 20:35
diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff
index 512d9fe172b..474d2df7aad 100644
--- a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff
+++ b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff
@@ -19,6 +19,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/simplify-arm-identity.rs:18:9: 18:10
+          Deinit(_1);                      // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
           ((_1 as Foo).0: u8) = const 0_u8; // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
           discriminant(_1) = 0;            // scope 0 at $DIR/simplify-arm-identity.rs:18:18: 18:29
           StorageLive(_2);                 // scope 1 at $DIR/simplify-arm-identity.rs:19:18: 22:6
@@ -27,6 +28,7 @@
       }
   
       bb1: {
+          Deinit(_2);                      // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
           ((_2 as Foo).0: u8) = const 0_u8; // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
           discriminant(_2) = 0;            // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
           goto -> bb4;                     // scope 1 at $DIR/simplify-arm-identity.rs:21:21: 21:32
@@ -41,6 +43,7 @@
           _4 = ((_1 as Foo).0: u8);        // scope 1 at $DIR/simplify-arm-identity.rs:20:18: 20:19
           StorageLive(_5);                 // scope 3 at $DIR/simplify-arm-identity.rs:20:33: 20:34
           _5 = _4;                         // scope 3 at $DIR/simplify-arm-identity.rs:20:33: 20:34
+          Deinit(_2);                      // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
           ((_2 as Foo).0: u8) = move _5;   // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
           discriminant(_2) = 0;            // scope 3 at $DIR/simplify-arm-identity.rs:20:24: 20:35
           StorageDead(_5);                 // scope 3 at $DIR/simplify-arm-identity.rs:20:34: 20:35
diff --git a/src/test/mir-opt/simplify_locals.d1.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.d1.SimplifyLocals.diff
index 97cbf2acf06..6d76b51cb19 100644
--- a/src/test/mir-opt/simplify_locals.d1.SimplifyLocals.diff
+++ b/src/test/mir-opt/simplify_locals.d1.SimplifyLocals.diff
@@ -9,6 +9,7 @@
   
       bb0: {
 -         StorageLive(_1);                 // scope 0 at $DIR/simplify-locals.rs:22:13: 22:17
+-         Deinit(_1);                      // scope 0 at $DIR/simplify-locals.rs:22:13: 22:17
 -         discriminant(_1) = 0;            // scope 0 at $DIR/simplify-locals.rs:22:13: 22:17
 -         StorageDead(_1);                 // scope 0 at $DIR/simplify-locals.rs:22:17: 22:18
           return;                          // scope 0 at $DIR/simplify-locals.rs:23:2: 23:2
diff --git a/src/test/mir-opt/simplify_locals.d2.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.d2.SimplifyLocals.diff
index cf20e83ef06..4a386d46468 100644
--- a/src/test/mir-opt/simplify_locals.d2.SimplifyLocals.diff
+++ b/src/test/mir-opt/simplify_locals.d2.SimplifyLocals.diff
@@ -9,10 +9,13 @@
   
       bb0: {
 -         StorageLive(_1);                 // scope 0 at $DIR/simplify-locals.rs:28:22: 28:26
+-         Deinit(_1);                      // scope 0 at $DIR/simplify-locals.rs:28:22: 28:26
 -         discriminant(_1) = 1;            // scope 0 at $DIR/simplify-locals.rs:28:22: 28:26
 -         StorageLive(_2);                 // scope 0 at $DIR/simplify-locals.rs:28:5: 28:17
 -         StorageLive(_3);                 // scope 0 at $DIR/simplify-locals.rs:28:11: 28:15
+-         Deinit(_3);                      // scope 0 at $DIR/simplify-locals.rs:28:11: 28:15
 -         discriminant(_3) = 0;            // scope 0 at $DIR/simplify-locals.rs:28:11: 28:15
+-         Deinit(_2);                      // scope 0 at $DIR/simplify-locals.rs:28:6: 28:16
 -         (_2.0: i32) = const 10_i32;      // scope 0 at $DIR/simplify-locals.rs:28:6: 28:16
 -         (_2.1: E) = const E::A;          // scope 0 at $DIR/simplify-locals.rs:28:6: 28:16
 -                                          // mir::Constant
diff --git a/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff
index fdd838f9a90..a8cc61f0526 100644
--- a/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff
+++ b/src/test/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals.diff
@@ -18,9 +18,12 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:30: 4:69
           StorageLive(_2);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:31: 4:49
+          Deinit(_2);                      // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:31: 4:49
           discriminant(_2) = 0;            // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:31: 4:49
           StorageLive(_3);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:51: 4:68
+          Deinit(_3);                      // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:51: 4:68
           discriminant(_3) = 0;            // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:51: 4:68
+          Deinit(_1);                      // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:30: 4:69
           (_1.0: std::option::Option<u8>) = move _2; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:30: 4:69
           (_1.1: std::option::Option<T>) = move _3; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:30: 4:69
           StorageDead(_3);                 // scope 0 at $DIR/simplify-locals-fixedpoint.rs:4:68: 4:69
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
index 598e8247efc..55b9838031c 100644
--- a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
+++ b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
@@ -47,6 +47,7 @@
 -         StorageLive(_9);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34
 -         StorageLive(_10);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30
 -         StorageLive(_11);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28
+-         Deinit(_11);                     // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28
 -         (_11.0: u8) = const 40_u8;       // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28
 -         _10 = const 40_u8;               // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30
 -         _9 = const 42_u8;                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff
index e139eedf3a0..aa9f0c18d09 100644
--- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff
+++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff
@@ -4,7 +4,7 @@
   fn map(_1: Option<Box<()>>) -> Option<Box<()>> {
       debug x => _1;                       // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:8: 3:9
       let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:31: 3:46
--     let mut _2: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13
+      let mut _2: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13
 -     let _3: std::boxed::Box<()>;         // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15
 -     let mut _4: std::boxed::Box<()>;     // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:25: 6:26
 -     let mut _5: bool;                    // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2
@@ -17,8 +17,24 @@
       bb0: {
 -         _5 = const false;                // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:11: 4:12
 -         _5 = const true;                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:11: 4:12
--         _2 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:11: 4:12
-          _0 = move _1;                    // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27
+          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:11: 4:12
+          switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:5: 4:12
+      }
+  
+      bb1: {
+          ((_0 as Some).0: std::boxed::Box<()>) = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15
+          Deinit(_0);                      // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27
+          discriminant(_0) = 1;            // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27
+          goto -> bb3;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:26: 6:27
+      }
+  
+      bb2: {
+          Deinit(_0);                      // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:17: 5:21
+          discriminant(_0) = 0;            // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:17: 5:21
+          goto -> bb3;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:17: 5:21
+      }
+  
+      bb3: {
 -         _6 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2
           return;                          // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:2: 8:2
       }
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff
index e139eedf3a0..aa9f0c18d09 100644
--- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff
+++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff
@@ -4,7 +4,7 @@
   fn map(_1: Option<Box<()>>) -> Option<Box<()>> {
       debug x => _1;                       // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:8: 3:9
       let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:31: 3:46
--     let mut _2: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13
+      let mut _2: isize;                   // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13
 -     let _3: std::boxed::Box<()>;         // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15
 -     let mut _4: std::boxed::Box<()>;     // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:25: 6:26
 -     let mut _5: bool;                    // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2
@@ -17,8 +17,24 @@
       bb0: {
 -         _5 = const false;                // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:11: 4:12
 -         _5 = const true;                 // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:11: 4:12
--         _2 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:11: 4:12
-          _0 = move _1;                    // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27
+          _2 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:11: 4:12
+          switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:5: 4:12
+      }
+  
+      bb1: {
+          ((_0 as Some).0: std::boxed::Box<()>) = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15
+          Deinit(_0);                      // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27
+          discriminant(_0) = 1;            // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27
+          goto -> bb3;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:26: 6:27
+      }
+  
+      bb2: {
+          Deinit(_0);                      // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:17: 5:21
+          discriminant(_0) = 0;            // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:17: 5:21
+          goto -> bb3;                     // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:17: 5:21
+      }
+  
+      bb3: {
 -         _6 = discriminant(_1);           // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2
           return;                          // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:2: 8:2
       }
diff --git a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff
index 9f6585e9168..1e0071353f9 100644
--- a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff
+++ b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff
@@ -15,48 +15,100 @@
       let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:23:12: 23:13
       let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:25:8: 25:9
       scope 1 {
-          debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10
+-         debug y => _2;                   // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10
++         debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10
       }
       scope 2 {
-          debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
+-         debug e => _6;                   // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
++         debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
           scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50
-              debug t => ((_0 as Err).0: i32); // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+-             debug t => _9;               // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
++             debug t => ((_0 as Err).0: i32); // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
           }
           scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51
-              debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:12:21: 12:22
+-             debug e => _8;               // in scope 6 at $DIR/simplify_try.rs:12:21: 12:22
++             debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:12:21: 12:22
           }
       }
       scope 3 {
-          debug v => ((_0 as Ok).0: u32);  // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
+-         debug v => _10;                  // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
++         debug v => ((_0 as Ok).0: u32);  // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
       }
       scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33
 -         debug r => _4;                   // in scope 4 at $DIR/simplify_try.rs:8:22: 8:23
-+         debug r => _0;                   // in scope 4 at $DIR/simplify_try.rs:8:22: 8:23
++         debug r => _3;                   // in scope 4 at $DIR/simplify_try.rs:8:22: 8:23
       }
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:21:9: 21:10
+-         StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:21:9: 21:10
 -         StorageLive(_3);                 // scope 0 at $DIR/simplify_try.rs:21:19: 21:33
 -         StorageLive(_4);                 // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
 -         _4 = _1;                         // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
 -         _3 = move _4;                    // scope 4 at $DIR/simplify_try.rs:9:5: 9:6
 -         StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:21:32: 21:33
--         _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:21:19: 21:33
++         nop;                             // scope 0 at $DIR/simplify_try.rs:21:9: 21:10
 +         nop;                             // scope 0 at $DIR/simplify_try.rs:21:19: 21:33
 +         nop;                             // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
-+         _0 = _1;                         // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
++         _3 = _1;                         // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
 +         nop;                             // scope 4 at $DIR/simplify_try.rs:9:5: 9:6
 +         nop;                             // scope 0 at $DIR/simplify_try.rs:21:32: 21:33
-+         _5 = discriminant(_0);           // scope 0 at $DIR/simplify_try.rs:21:19: 21:33
-          goto -> bb1;                     // scope 0 at $DIR/simplify_try.rs:21:13: 21:33
+          _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:21:19: 21:33
+          switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:21:13: 21:33
       }
   
       bb1: {
--         _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+-         StorageLive(_10);                // scope 0 at $DIR/simplify_try.rs:23:12: 23:13
+-         _10 = ((_3 as Ok).0: u32);       // scope 0 at $DIR/simplify_try.rs:23:12: 23:13
+-         _2 = _10;                        // scope 3 at $DIR/simplify_try.rs:23:18: 23:19
+-         StorageDead(_10);                // scope 0 at $DIR/simplify_try.rs:23:18: 23:19
 -         StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
+-         StorageLive(_11);                // scope 1 at $DIR/simplify_try.rs:25:8: 25:9
+-         _11 = _2;                        // scope 1 at $DIR/simplify_try.rs:25:8: 25:9
++         nop;                             // scope 0 at $DIR/simplify_try.rs:23:12: 23:13
++         ((_0 as Ok).0: u32) = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:23:12: 23:13
++         nop;                             // scope 3 at $DIR/simplify_try.rs:23:18: 23:19
++         nop;                             // scope 0 at $DIR/simplify_try.rs:23:18: 23:19
++         nop;                             // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
++         nop;                             // scope 1 at $DIR/simplify_try.rs:25:8: 25:9
++         nop;                             // scope 1 at $DIR/simplify_try.rs:25:8: 25:9
+          Deinit(_0);                      // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+-         ((_0 as Ok).0: u32) = move _11;  // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
 +         nop;                             // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+          discriminant(_0) = 0;            // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+-         StorageDead(_11);                // scope 1 at $DIR/simplify_try.rs:25:9: 25:10
+-         StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:26:1: 26:2
++         nop;                             // scope 1 at $DIR/simplify_try.rs:25:9: 25:10
++         nop;                             // scope 0 at $DIR/simplify_try.rs:26:1: 26:2
+          return;                          // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
+      }
+  
+      bb2: {
+-         StorageLive(_6);                 // scope 0 at $DIR/simplify_try.rs:22:13: 22:14
+-         _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify_try.rs:22:13: 22:14
+-         StorageLive(_8);                 // scope 2 at $DIR/simplify_try.rs:22:37: 22:50
+-         StorageLive(_9);                 // scope 2 at $DIR/simplify_try.rs:22:48: 22:49
+-         _9 = _6;                         // scope 2 at $DIR/simplify_try.rs:22:48: 22:49
+-         _8 = move _9;                    // scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+-         StorageDead(_9);                 // scope 2 at $DIR/simplify_try.rs:22:49: 22:50
+-         ((_0 as Err).0: i32) = move _8;  // scope 6 at $DIR/simplify_try.rs:13:9: 13:10
++         nop;                             // scope 0 at $DIR/simplify_try.rs:22:13: 22:14
++         ((_0 as Err).0: i32) = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:22:13: 22:14
++         nop;                             // scope 2 at $DIR/simplify_try.rs:22:37: 22:50
++         nop;                             // scope 2 at $DIR/simplify_try.rs:22:48: 22:49
++         nop;                             // scope 2 at $DIR/simplify_try.rs:22:48: 22:49
++         nop;                             // scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
++         nop;                             // scope 2 at $DIR/simplify_try.rs:22:49: 22:50
++         nop;                             // scope 6 at $DIR/simplify_try.rs:13:9: 13:10
+          Deinit(_0);                      // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
+          discriminant(_0) = 1;            // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
+-         StorageDead(_8);                 // scope 2 at $DIR/simplify_try.rs:22:50: 22:51
+-         StorageDead(_6);                 // scope 0 at $DIR/simplify_try.rs:22:50: 22:51
+-         StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
+-         StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:26:1: 26:2
++         nop;                             // scope 2 at $DIR/simplify_try.rs:22:50: 22:51
++         nop;                             // scope 0 at $DIR/simplify_try.rs:22:50: 22:51
 +         nop;                             // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
-          StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:26:1: 26:2
++         nop;                             // scope 0 at $DIR/simplify_try.rs:26:1: 26:2
           return;                          // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
       }
   }
diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff
index b568b3a479f..01e76109ada 100644
--- a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff
+++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff
@@ -15,24 +15,19 @@
       let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:23:12: 23:13
       let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:25:8: 25:9
       scope 1 {
--         debug y => _2;                   // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10
-+         debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10
+          debug y => _2;                   // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10
       }
       scope 2 {
--         debug e => _6;                   // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
-+         debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
+          debug e => _6;                   // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
           scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50
--             debug t => _9;               // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
-+             debug t => ((_0 as Err).0: i32); // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+              debug t => _9;               // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
           }
           scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51
--             debug e => _8;               // in scope 6 at $DIR/simplify_try.rs:12:21: 12:22
-+             debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:12:21: 12:22
+              debug e => _8;               // in scope 6 at $DIR/simplify_try.rs:12:21: 12:22
           }
       }
       scope 3 {
--         debug v => _10;                  // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
-+         debug v => ((_0 as Ok).0: u32);  // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
+          debug v => _10;                  // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
       }
       scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33
           debug r => _4;                   // in scope 4 at $DIR/simplify_try.rs:8:22: 8:23
@@ -50,34 +45,34 @@
       }
   
       bb1: {
--         StorageLive(_10);                // scope 0 at $DIR/simplify_try.rs:23:12: 23:13
--         _10 = ((_3 as Ok).0: u32);       // scope 0 at $DIR/simplify_try.rs:23:12: 23:13
--         _2 = _10;                        // scope 3 at $DIR/simplify_try.rs:23:18: 23:19
--         StorageDead(_10);                // scope 0 at $DIR/simplify_try.rs:23:18: 23:19
-+         _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+          StorageLive(_10);                // scope 0 at $DIR/simplify_try.rs:23:12: 23:13
+          _10 = ((_3 as Ok).0: u32);       // scope 0 at $DIR/simplify_try.rs:23:12: 23:13
+          _2 = _10;                        // scope 3 at $DIR/simplify_try.rs:23:18: 23:19
+          StorageDead(_10);                // scope 0 at $DIR/simplify_try.rs:23:18: 23:19
           StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
--         StorageLive(_11);                // scope 1 at $DIR/simplify_try.rs:25:8: 25:9
--         _11 = _2;                        // scope 1 at $DIR/simplify_try.rs:25:8: 25:9
--         ((_0 as Ok).0: u32) = move _11;  // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
--         discriminant(_0) = 0;            // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
--         StorageDead(_11);                // scope 1 at $DIR/simplify_try.rs:25:9: 25:10
+          StorageLive(_11);                // scope 1 at $DIR/simplify_try.rs:25:8: 25:9
+          _11 = _2;                        // scope 1 at $DIR/simplify_try.rs:25:8: 25:9
+          Deinit(_0);                      // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+          ((_0 as Ok).0: u32) = move _11;  // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+          discriminant(_0) = 0;            // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+          StorageDead(_11);                // scope 1 at $DIR/simplify_try.rs:25:9: 25:10
           StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:26:1: 26:2
           return;                          // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
       }
   
       bb2: {
--         StorageLive(_6);                 // scope 0 at $DIR/simplify_try.rs:22:13: 22:14
--         _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify_try.rs:22:13: 22:14
--         StorageLive(_8);                 // scope 2 at $DIR/simplify_try.rs:22:37: 22:50
--         StorageLive(_9);                 // scope 2 at $DIR/simplify_try.rs:22:48: 22:49
--         _9 = _6;                         // scope 2 at $DIR/simplify_try.rs:22:48: 22:49
--         _8 = move _9;                    // scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
--         StorageDead(_9);                 // scope 2 at $DIR/simplify_try.rs:22:49: 22:50
--         ((_0 as Err).0: i32) = move _8;  // scope 6 at $DIR/simplify_try.rs:13:9: 13:10
--         discriminant(_0) = 1;            // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
--         StorageDead(_8);                 // scope 2 at $DIR/simplify_try.rs:22:50: 22:51
--         StorageDead(_6);                 // scope 0 at $DIR/simplify_try.rs:22:50: 22:51
-+         _0 = move _3;                    // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
+          StorageLive(_6);                 // scope 0 at $DIR/simplify_try.rs:22:13: 22:14
+          _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify_try.rs:22:13: 22:14
+          StorageLive(_8);                 // scope 2 at $DIR/simplify_try.rs:22:37: 22:50
+          StorageLive(_9);                 // scope 2 at $DIR/simplify_try.rs:22:48: 22:49
+          _9 = _6;                         // scope 2 at $DIR/simplify_try.rs:22:48: 22:49
+          _8 = move _9;                    // scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+          StorageDead(_9);                 // scope 2 at $DIR/simplify_try.rs:22:49: 22:50
+          ((_0 as Err).0: i32) = move _8;  // scope 6 at $DIR/simplify_try.rs:13:9: 13:10
+          Deinit(_0);                      // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
+          discriminant(_0) = 1;            // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
+          StorageDead(_8);                 // scope 2 at $DIR/simplify_try.rs:22:50: 22:51
+          StorageDead(_6);                 // scope 0 at $DIR/simplify_try.rs:22:50: 22:51
           StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
           StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:26:1: 26:2
           return;                          // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir
index 24d8f5fba61..56af6730966 100644
--- a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir
+++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir
@@ -14,19 +14,19 @@ fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> {
     let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:23:12: 23:13
     let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:25:8: 25:9
     scope 1 {
-        debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10
+        debug y => _2;                   // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10
     }
     scope 2 {
-        debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
+        debug e => _6;                   // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
         scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50
-            debug t => ((_0 as Err).0: i32); // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+            debug t => _9;               // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
         }
         scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51
-            debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:12:21: 12:22
+            debug e => _8;               // in scope 6 at $DIR/simplify_try.rs:12:21: 12:22
         }
     }
     scope 3 {
-        debug v => ((_0 as Ok).0: u32);  // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
+        debug v => _10;                  // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
     }
     scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33
         debug r => _4;                   // in scope 4 at $DIR/simplify_try.rs:8:22: 8:23
@@ -40,11 +40,38 @@ fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> {
         _3 = move _4;                    // scope 4 at $DIR/simplify_try.rs:9:5: 9:6
         StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:21:32: 21:33
         _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:21:19: 21:33
-        goto -> bb1;                     // scope 0 at $DIR/simplify_try.rs:21:13: 21:33
+        switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:21:13: 21:33
     }
 
     bb1: {
-        _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+        StorageLive(_10);                // scope 0 at $DIR/simplify_try.rs:23:12: 23:13
+        _10 = ((_3 as Ok).0: u32);       // scope 0 at $DIR/simplify_try.rs:23:12: 23:13
+        _2 = _10;                        // scope 3 at $DIR/simplify_try.rs:23:18: 23:19
+        StorageDead(_10);                // scope 0 at $DIR/simplify_try.rs:23:18: 23:19
+        StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
+        StorageLive(_11);                // scope 1 at $DIR/simplify_try.rs:25:8: 25:9
+        _11 = _2;                        // scope 1 at $DIR/simplify_try.rs:25:8: 25:9
+        Deinit(_0);                      // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+        ((_0 as Ok).0: u32) = move _11;  // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+        discriminant(_0) = 0;            // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+        StorageDead(_11);                // scope 1 at $DIR/simplify_try.rs:25:9: 25:10
+        StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:26:1: 26:2
+        return;                          // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
+    }
+
+    bb2: {
+        StorageLive(_6);                 // scope 0 at $DIR/simplify_try.rs:22:13: 22:14
+        _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify_try.rs:22:13: 22:14
+        StorageLive(_8);                 // scope 2 at $DIR/simplify_try.rs:22:37: 22:50
+        StorageLive(_9);                 // scope 2 at $DIR/simplify_try.rs:22:48: 22:49
+        _9 = _6;                         // scope 2 at $DIR/simplify_try.rs:22:48: 22:49
+        _8 = move _9;                    // scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
+        StorageDead(_9);                 // scope 2 at $DIR/simplify_try.rs:22:49: 22:50
+        ((_0 as Err).0: i32) = move _8;  // scope 6 at $DIR/simplify_try.rs:13:9: 13:10
+        Deinit(_0);                      // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
+        discriminant(_0) = 1;            // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
+        StorageDead(_8);                 // scope 2 at $DIR/simplify_try.rs:22:50: 22:51
+        StorageDead(_6);                 // scope 0 at $DIR/simplify_try.rs:22:50: 22:51
         StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
         StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:26:1: 26:2
         return;                          // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir
index e99795ffe21..4407e8e36fd 100644
--- a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir
+++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir
@@ -3,6 +3,8 @@
 fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> {
     debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:20:17: 20:18
     let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57
+    let mut _2: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:21:19: 21:33
+    let mut _3: isize;                   // in scope 0 at $DIR/simplify_try.rs:22:9: 22:15
     scope 1 {
         debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10
     }
@@ -19,11 +21,26 @@ fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> {
         debug v => ((_0 as Ok).0: u32);  // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
     }
     scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33
-        debug r => _0;                   // in scope 4 at $DIR/simplify_try.rs:8:22: 8:23
+        debug r => _2;                   // in scope 4 at $DIR/simplify_try.rs:8:22: 8:23
     }
 
     bb0: {
-        _0 = _1;                         // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
+        _2 = _1;                         // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
+        _3 = discriminant(_2);           // scope 0 at $DIR/simplify_try.rs:21:19: 21:33
+        switchInt(move _3) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:21:13: 21:33
+    }
+
+    bb1: {
+        ((_0 as Ok).0: u32) = ((_2 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:23:12: 23:13
+        Deinit(_0);                      // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+        discriminant(_0) = 0;            // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+        return;                          // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
+    }
+
+    bb2: {
+        ((_0 as Err).0: i32) = ((_2 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:22:13: 22:14
+        Deinit(_0);                      // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
+        discriminant(_0) = 1;            // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
         return;                          // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
     }
 }
diff --git a/src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir b/src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir
index 75cc100def5..2b79a69b93b 100644
--- a/src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir
+++ b/src/test/mir-opt/uninhabited_enum_branching.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir
@@ -15,6 +15,7 @@ fn main() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:20:5: 24:6
         StorageLive(_2);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
+        Deinit(_2);                      // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
         discriminant(_2) = 2;            // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
         _3 = discriminant(_2);           // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
         StorageLive(_5);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:23:21: 23:24
@@ -28,6 +29,7 @@ fn main() -> () {
         StorageDead(_1);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:24:6: 24:7
         StorageLive(_6);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:26:5: 29:6
         StorageLive(_7);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
+        Deinit(_7);                      // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
         discriminant(_7) = 0;            // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
         _8 = discriminant(_7);           // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
         switchInt(move _8) -> [4_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/uninhabited_enum_branching.rs:26:5: 26:19
diff --git a/src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff b/src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff
index f173d002e2d..fe87bbd8c0b 100644
--- a/src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff
+++ b/src/test/mir-opt/uninhabited_enum_branching.main.UninhabitedEnumBranching.diff
@@ -16,6 +16,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:20:5: 24:6
           StorageLive(_2);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
+          Deinit(_2);                      // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
           discriminant(_2) = 2;            // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
           _3 = discriminant(_2);           // scope 0 at $DIR/uninhabited_enum_branching.rs:20:11: 20:19
 -         switchInt(move _3) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/uninhabited_enum_branching.rs:20:5: 20:19
@@ -57,6 +58,7 @@
           StorageDead(_1);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:24:6: 24:7
           StorageLive(_6);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:26:5: 29:6
           StorageLive(_7);                 // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
+          Deinit(_7);                      // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
           discriminant(_7) = 0;            // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
           _8 = discriminant(_7);           // scope 0 at $DIR/uninhabited_enum_branching.rs:26:11: 26:19
           switchInt(move _8) -> [4_isize: bb6, otherwise: bb5]; // scope 0 at $DIR/uninhabited_enum_branching.rs:26:5: 26:19
diff --git a/src/test/mir-opt/uninhabited_enum_branching2.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir b/src/test/mir-opt/uninhabited_enum_branching2.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir
index 94fba142e00..27f9c8b7f8f 100644
--- a/src/test/mir-opt/uninhabited_enum_branching2.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir
+++ b/src/test/mir-opt/uninhabited_enum_branching2.main.SimplifyCfg-after-uninhabited-enum-branching.after.mir
@@ -22,7 +22,9 @@ fn main() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:9: 19:13
         StorageLive(_2);                 // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:38: 19:46
+        Deinit(_2);                      // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:38: 19:46
         discriminant(_2) = 2;            // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:38: 19:46
+        Deinit(_1);                      // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:16: 19:48
         (_1.0: u32) = const 51_u32;      // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:16: 19:48
         (_1.1: Test1) = move _2;         // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:16: 19:48
         StorageDead(_2);                 // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:47: 19:48
diff --git a/src/test/mir-opt/uninhabited_enum_branching2.main.UninhabitedEnumBranching.diff b/src/test/mir-opt/uninhabited_enum_branching2.main.UninhabitedEnumBranching.diff
index 84ee885d1f5..8622fccec88 100644
--- a/src/test/mir-opt/uninhabited_enum_branching2.main.UninhabitedEnumBranching.diff
+++ b/src/test/mir-opt/uninhabited_enum_branching2.main.UninhabitedEnumBranching.diff
@@ -23,7 +23,9 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:9: 19:13
           StorageLive(_2);                 // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:38: 19:46
+          Deinit(_2);                      // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:38: 19:46
           discriminant(_2) = 2;            // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:38: 19:46
+          Deinit(_1);                      // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:16: 19:48
           (_1.0: u32) = const 51_u32;      // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:16: 19:48
           (_1.1: Test1) = move _2;         // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:16: 19:48
           StorageDead(_2);                 // scope 0 at $DIR/uninhabited_enum_branching2.rs:19:47: 19:48
diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir
index 832f18e14c2..d106da84fc7 100644
--- a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir
+++ b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir
@@ -4,6 +4,7 @@ fn Test::X(_1: usize) -> Test {
     let mut _0: Test;                    // return place in scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
 
     bb0: {
+        Deinit(_0);                      // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
         ((_0 as X).0: usize) = move _1;  // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
         discriminant(_0) = 0;            // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
         return;                          // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir
index 832f18e14c2..d106da84fc7 100644
--- a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir
+++ b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir
@@ -4,6 +4,7 @@ fn Test::X(_1: usize) -> Test {
     let mut _0: Test;                    // return place in scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
 
     bb0: {
+        Deinit(_0);                      // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
         ((_0 as X).0: usize) = move _1;  // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
         discriminant(_0) = 0;            // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
         return;                          // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff
index 8ecda3a1ae2..0529b15522e 100644
--- a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff
+++ b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff
@@ -19,6 +19,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:6:9: 6:15
           _1 = const 0_i32;                // scope 0 at $DIR/while_let_loops.rs:6:18: 6:19
           StorageLive(_3);                 // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32
+          Deinit(_3);                      // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32
           discriminant(_3) = 0;            // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32
 -         _4 = discriminant(_3);           // scope 1 at $DIR/while_let_loops.rs:7:15: 7:25
 -         switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 1 at $DIR/while_let_loops.rs:7:15: 7:25
diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff
index 8ecda3a1ae2..0529b15522e 100644
--- a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff
+++ b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff
@@ -19,6 +19,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:6:9: 6:15
           _1 = const 0_i32;                // scope 0 at $DIR/while_let_loops.rs:6:18: 6:19
           StorageLive(_3);                 // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32
+          Deinit(_3);                      // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32
           discriminant(_3) = 0;            // scope 1 at $DIR/while_let_loops.rs:7:28: 7:32
 -         _4 = discriminant(_3);           // scope 1 at $DIR/while_let_loops.rs:7:15: 7:25
 -         switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 1 at $DIR/while_let_loops.rs:7:15: 7:25
diff --git a/src/test/run-make/translation/Makefile b/src/test/run-make/translation/Makefile
index 22a3bf57ecf..bfff75e7acb 100644
--- a/src/test/run-make/translation/Makefile
+++ b/src/test/run-make/translation/Makefile
@@ -15,7 +15,9 @@ normal: basic-translation.rs
 custom: basic-translation.rs basic-translation.ftl
 	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/basic-translation.ftl 2>&1 | grep "this is a test message"
 
-# Make a local copy of the sysroot and add the custom locale to it.
+# Check that a locale can be loaded from the sysroot given a language
+# identifier by making a local copy of the sysroot and adding the custom locale
+# to it.
 sysroot: basic-translation.rs basic-translation.ftl
 	mkdir $(FAKEROOT)
 	ln -s $(SYSROOT)/* $(FAKEROOT)
@@ -31,3 +33,27 @@ sysroot: basic-translation.rs basic-translation.ftl
 	mkdir -p $(FAKEROOT)/share/locale/zh-CN/
 	ln -s $(CURDIR)/basic-translation.ftl $(FAKEROOT)/share/locale/zh-CN/basic-translation.ftl
 	$(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | grep "this is a test message"
+
+# Check that the compiler errors out when the sysroot requested cannot be
+# found. This test might start failing if there actually exists a Klingon
+# translation of rustc's error messages.
+sysroot-missing: 
+	$(RUSTC) $< -Ztranslate-lang=tlh 2>&1 || grep "missing locale directory"
+
+# Check that the compiler errors out when the sysroot requested cannot be
+# found. This test might start failing if there actually exists a Klingon
+# translation of rustc's error messages.
+sysroot-invalid: basic-translation.rs basic-translation.ftl
+	mkdir $(FAKEROOT)
+	ln -s $(SYSROOT)/* $(FAKEROOT)
+	rm -f $(FAKEROOT)/lib
+	mkdir $(FAKEROOT)/lib
+	ln -s $(SYSROOT)/lib/* $(FAKEROOT)/lib
+	rm -f $(FAKEROOT)/lib/rustlib
+	mkdir $(FAKEROOT)/lib/rustlib
+	ln -s $(SYSROOT)/lib/rustlib/* $(FAKEROOT)/lib/rustlib
+	rm -f $(FAKEROOT)/lib/rustlib/src
+	mkdir $(FAKEROOT)/lib/rustlib/src
+	ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src
+	touch $(FAKEROOT)/share/locale/zh-CN/
+	$(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 || grep "`\$sysroot/share/locales/\$locale` is not a directory"
diff --git a/src/test/rustdoc-ui/failed-doctest-output-windows.rs b/src/test/rustdoc-ui/failed-doctest-output-windows.rs
new file mode 100644
index 00000000000..4cd9993d8d5
--- /dev/null
+++ b/src/test/rustdoc-ui/failed-doctest-output-windows.rs
@@ -0,0 +1,28 @@
+// only-windows
+// There's a parallel generic version of this test for non-windows platforms.
+
+// Issue #51162: A failed doctest was not printing its stdout/stderr
+// FIXME: if/when the output of the test harness can be tested on its own, this test should be
+// adapted to use that, and that normalize line can go away
+
+// compile-flags:--test --test-args --test-threads=1
+// rustc-env:RUST_BACKTRACE=0
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// failure-status: 101
+
+// doctest fails at runtime
+/// ```
+/// println!("stdout 1");
+/// eprintln!("stderr 1");
+/// println!("stdout 2");
+/// eprintln!("stderr 2");
+/// panic!("oh no");
+/// ```
+pub struct SomeStruct;
+
+// doctest fails at compile time
+/// ```
+/// no
+/// ```
+pub struct OtherStruct;
diff --git a/src/test/rustdoc-ui/failed-doctest-output-windows.stdout b/src/test/rustdoc-ui/failed-doctest-output-windows.stdout
new file mode 100644
index 00000000000..6c147054da3
--- /dev/null
+++ b/src/test/rustdoc-ui/failed-doctest-output-windows.stdout
@@ -0,0 +1,39 @@
+
+running 2 tests
+test $DIR/failed-doctest-output-windows.rs - OtherStruct (line 25) ... FAILED
+test $DIR/failed-doctest-output-windows.rs - SomeStruct (line 15) ... FAILED
+
+failures:
+
+---- $DIR/failed-doctest-output-windows.rs - OtherStruct (line 25) stdout ----
+error[E0425]: cannot find value `no` in this scope
+  --> $DIR/failed-doctest-output-windows.rs:26:1
+   |
+LL | no
+   | ^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
+Couldn't compile the test.
+---- $DIR/failed-doctest-output-windows.rs - SomeStruct (line 15) stdout ----
+Test executable failed (exit code: 101).
+
+stdout:
+stdout 1
+stdout 2
+
+stderr:
+stderr 1
+stderr 2
+thread 'main' panicked at 'oh no', $DIR/failed-doctest-output-windows.rs:7:1
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+
+
+
+failures:
+    $DIR/failed-doctest-output-windows.rs - OtherStruct (line 25)
+    $DIR/failed-doctest-output-windows.rs - SomeStruct (line 15)
+
+test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/failed-doctest-output.rs b/src/test/rustdoc-ui/failed-doctest-output.rs
index 92473b49e14..42de954d052 100644
--- a/src/test/rustdoc-ui/failed-doctest-output.rs
+++ b/src/test/rustdoc-ui/failed-doctest-output.rs
@@ -1,3 +1,6 @@
+// ignore-windows
+// There's a parallel version of this test for Windows.
+
 // Issue #51162: A failed doctest was not printing its stdout/stderr
 // FIXME: if/when the output of the test harness can be tested on its own, this test should be
 // adapted to use that, and that normalize line can go away
diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout
index 6dfe648f854..630198a561a 100644
--- a/src/test/rustdoc-ui/failed-doctest-output.stdout
+++ b/src/test/rustdoc-ui/failed-doctest-output.stdout
@@ -1,13 +1,13 @@
 
 running 2 tests
-test $DIR/failed-doctest-output.rs - OtherStruct (line 22) ... FAILED
-test $DIR/failed-doctest-output.rs - SomeStruct (line 12) ... FAILED
+test $DIR/failed-doctest-output.rs - OtherStruct (line 25) ... FAILED
+test $DIR/failed-doctest-output.rs - SomeStruct (line 15) ... FAILED
 
 failures:
 
----- $DIR/failed-doctest-output.rs - OtherStruct (line 22) stdout ----
+---- $DIR/failed-doctest-output.rs - OtherStruct (line 25) stdout ----
 error[E0425]: cannot find value `no` in this scope
-  --> $DIR/failed-doctest-output.rs:23:1
+  --> $DIR/failed-doctest-output.rs:26:1
    |
 LL | no
    | ^^ not found in this scope
@@ -16,8 +16,8 @@ error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0425`.
 Couldn't compile the test.
----- $DIR/failed-doctest-output.rs - SomeStruct (line 12) stdout ----
-Test executable failed (exit code 101).
+---- $DIR/failed-doctest-output.rs - SomeStruct (line 15) stdout ----
+Test executable failed (exit status: 101).
 
 stdout:
 stdout 1
@@ -32,8 +32,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 
 failures:
-    $DIR/failed-doctest-output.rs - OtherStruct (line 22)
-    $DIR/failed-doctest-output.rs - SomeStruct (line 12)
+    $DIR/failed-doctest-output.rs - OtherStruct (line 25)
+    $DIR/failed-doctest-output.rs - SomeStruct (line 15)
 
 test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/test/rustdoc/rfc-2632-const-trait-impl.rs b/src/test/rustdoc/rfc-2632-const-trait-impl.rs
index c5353c4d5b5..f9173feeeec 100644
--- a/src/test/rustdoc/rfc-2632-const-trait-impl.rs
+++ b/src/test/rustdoc/rfc-2632-const-trait-impl.rs
@@ -1,5 +1,5 @@
 // Test that we do not currently display `~const` in rustdoc
-// as that syntax is currently provisional; `~const Drop` has
+// as that syntax is currently provisional; `~const Destruct` has
 // no effect on stable code so it should be hidden as well.
 //
 // To future blessers: make sure that `const_trait_impl` is
@@ -8,6 +8,8 @@
 #![feature(const_trait_impl)]
 #![crate_name = "foo"]
 
+use std::marker::Destruct;
+
 pub struct S<T>(T);
 
 // @!has foo/trait.Tr.html '//pre[@class="rust trait"]/code/a[@class="trait"]' '~const'
@@ -20,22 +22,36 @@ pub trait Tr<T> {
     // @!has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where"]' '~const'
     // @has - '//div[@id="method.a"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone'
     #[default_method_body_is_const]
-    fn a<A: ~const Clone>() where Option<A>: ~const Clone {}
+    fn a<A: ~const Clone + ~const Destruct>()
+    where
+        Option<A>: ~const Clone + ~const Destruct,
+    {
+    }
 }
 
 // @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]' '~const'
 // @has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/a[@class="trait"]' 'Clone'
 // @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/span[@class="where"]' '~const'
 // @has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/span[@class="where fmt-newline"]' ': Clone'
-impl<T: ~const Clone> const Tr<T> for T where Option<T>: ~const Clone {
-    fn a<A: ~const Clone>() where Option<A>: ~const Clone {}
+impl<T: ~const Clone + ~const Destruct> const Tr<T> for T
+where
+    Option<T>: ~const Clone + ~const Destruct,
+{
+    fn a<A: ~const Clone + ~const Destruct>()
+    where
+        Option<A>: ~const Clone + ~const Destruct,
+    {
+    }
 }
 
 // @!has foo/fn.foo.html '//pre[@class="rust fn"]/code/a[@class="trait"]' '~const'
 // @has - '//pre[@class="rust fn"]/code/a[@class="trait"]' 'Clone'
 // @!has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' '~const'
 // @has - '//pre[@class="rust fn"]/code/span[@class="where fmt-newline"]' ': Clone'
-pub const fn foo<F: ~const Clone>() where Option<F>: ~const Clone {
+pub const fn foo<F: ~const Clone + ~const Destruct>()
+where
+    Option<F>: ~const Clone + ~const Destruct,
+{
     F::a()
 }
 
@@ -44,7 +60,10 @@ impl<T> S<T> {
     // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/a[@class="trait"]' 'Clone'
     // @!has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where"]' '~const'
     // @has - '//section[@id="method.foo"]/h4[@class="code-header"]/span[@class="where fmt-newline"]' ': Clone'
-    pub const fn foo<B: ~const Clone>() where B: ~const Clone {
+    pub const fn foo<B: ~const Clone + ~const Destruct>()
+    where
+        B: ~const Clone + ~const Destruct,
+    {
         B::a()
     }
 }
diff --git a/src/test/ui/associated-type-bounds/binder-on-bound.rs b/src/test/ui/associated-type-bounds/binder-on-bound.rs
new file mode 100644
index 00000000000..0b4b24b9820
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/binder-on-bound.rs
@@ -0,0 +1,11 @@
+#![feature(generic_associated_types)]
+
+trait Trait {
+    type Bound<'a>;
+}
+
+fn foo() where Trait<for<'a> Bound<'a> = &'a ()> {
+    //~^ ERROR `for<...>` is not allowed on associated type bounds
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/binder-on-bound.stderr b/src/test/ui/associated-type-bounds/binder-on-bound.stderr
new file mode 100644
index 00000000000..3432672e03c
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/binder-on-bound.stderr
@@ -0,0 +1,8 @@
+error: `for<...>` is not allowed on associated type bounds
+  --> $DIR/binder-on-bound.rs:7:22
+   |
+LL | fn foo() where Trait<for<'a> Bound<'a> = &'a ()> {
+   |                      ^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/block-result/consider-removing-last-semi.stderr b/src/test/ui/block-result/consider-removing-last-semi.stderr
index 99a367bfccd..2412dcd32f7 100644
--- a/src/test/ui/block-result/consider-removing-last-semi.stderr
+++ b/src/test/ui/block-result/consider-removing-last-semi.stderr
@@ -7,7 +7,7 @@ LL | pub fn f() -> String {
    |        implicitly returns `()` as its body has no tail or `return` expression
 LL |     0u8;
 LL |     "bla".to_string();
-   |                      - help: consider removing this semicolon
+   |                      - help: remove this semicolon
 
 error[E0308]: mismatched types
   --> $DIR/consider-removing-last-semi.rs:8:15
@@ -18,7 +18,7 @@ LL | pub fn g() -> String {
    |        implicitly returns `()` as its body has no tail or `return` expression
 LL |     "this won't work".to_string();
 LL |     "removeme".to_string();
-   |                           - help: consider removing this semicolon
+   |                           - help: remove this semicolon
 
 error[E0308]: mismatched types
   --> $DIR/consider-removing-last-semi.rs:13:25
@@ -29,7 +29,7 @@ LL | pub fn macro_tests() -> u32 {
    |        implicitly returns `()` as its body has no tail or `return` expression
 ...
 LL |     mac!();
-   |           - help: consider removing this semicolon
+   |           - help: remove this semicolon
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/block-result/issue-11714.stderr b/src/test/ui/block-result/issue-11714.stderr
index 61991643a4a..5b8d96fd4eb 100644
--- a/src/test/ui/block-result/issue-11714.stderr
+++ b/src/test/ui/block-result/issue-11714.stderr
@@ -7,7 +7,7 @@ LL | fn blah() -> i32 {
    |    implicitly returns `()` as its body has no tail or `return` expression
 ...
 LL |     ;
-   |     - help: consider removing this semicolon
+   |     - help: remove this semicolon
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/block-result/issue-13428.stderr b/src/test/ui/block-result/issue-13428.stderr
index 2f24679cc95..a33448edff2 100644
--- a/src/test/ui/block-result/issue-13428.stderr
+++ b/src/test/ui/block-result/issue-13428.stderr
@@ -15,7 +15,7 @@ LL | fn bar() -> String {
    |    implicitly returns `()` as its body has no tail or `return` expression
 LL |     "foobar".to_string()
 LL |     ;
-   |     - help: consider removing this semicolon
+   |     - help: remove this semicolon
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/borrowck/suggest-local-var-for-vector.rs b/src/test/ui/borrowck/suggest-local-var-for-vector.rs
new file mode 100644
index 00000000000..40f013f6a78
--- /dev/null
+++ b/src/test/ui/borrowck/suggest-local-var-for-vector.rs
@@ -0,0 +1,4 @@
+fn main() {
+    let mut vec = vec![0u32; 420];
+    vec[vec.len() - 1] = 123; //~ ERROR cannot borrow `vec` as immutable because it is also borrowed as mutable
+}
diff --git a/src/test/ui/borrowck/suggest-local-var-for-vector.stderr b/src/test/ui/borrowck/suggest-local-var-for-vector.stderr
new file mode 100644
index 00000000000..615fffcd578
--- /dev/null
+++ b/src/test/ui/borrowck/suggest-local-var-for-vector.stderr
@@ -0,0 +1,24 @@
+error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mutable
+  --> $DIR/suggest-local-var-for-vector.rs:3:9
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |     ----^^^^^^^^^-----
+   |     |   |
+   |     |   immutable borrow occurs here
+   |     mutable borrow occurs here
+   |     mutable borrow later used here
+   |
+help: try adding a local storing this...
+  --> $DIR/suggest-local-var-for-vector.rs:3:9
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |         ^^^^^^^^^
+help: ...and then using that local here
+  --> $DIR/suggest-local-var-for-vector.rs:3:5
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs
new file mode 100644
index 00000000000..40f013f6a78
--- /dev/null
+++ b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs
@@ -0,0 +1,4 @@
+fn main() {
+    let mut vec = vec![0u32; 420];
+    vec[vec.len() - 1] = 123; //~ ERROR cannot borrow `vec` as immutable because it is also borrowed as mutable
+}
diff --git a/src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr
new file mode 100644
index 00000000000..e3a16eddfd5
--- /dev/null
+++ b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr
@@ -0,0 +1,24 @@
+error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mutable
+  --> $DIR/suggest-storing-local-var-for-vector.rs:3:9
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |     ----^^^^^^^^^-----
+   |     |   |
+   |     |   immutable borrow occurs here
+   |     mutable borrow occurs here
+   |     mutable borrow later used here
+   |
+help: try adding a local storing this...
+  --> $DIR/suggest-storing-local-var-for-vector.rs:3:9
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |         ^^^^^^^^^
+help: ...and then using that local here
+  --> $DIR/suggest-storing-local-var-for-vector.rs:3:5
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr
index 50d277a12f7..0f2daaf99d9 100644
--- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr
+++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr
@@ -54,6 +54,17 @@ LL |     i[i[3]] = 4;
    |     | immutable borrow occurs here
    |     mutable borrow occurs here
    |     mutable borrow later used here
+   |
+help: try adding a local storing this...
+  --> $DIR/two-phase-nonrecv-autoref.rs:138:7
+   |
+LL |     i[i[3]] = 4;
+   |       ^^^^
+help: ...and then using that local here
+  --> $DIR/two-phase-nonrecv-autoref.rs:138:5
+   |
+LL |     i[i[3]] = 4;
+   |     ^^^^^^^
 
 error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable
   --> $DIR/two-phase-nonrecv-autoref.rs:143:7
@@ -64,6 +75,17 @@ LL |     i[i[3]] = i[4];
    |     | immutable borrow occurs here
    |     mutable borrow occurs here
    |     mutable borrow later used here
+   |
+help: try adding a local storing this...
+  --> $DIR/two-phase-nonrecv-autoref.rs:143:7
+   |
+LL |     i[i[3]] = i[4];
+   |       ^^^^
+help: ...and then using that local here
+  --> $DIR/two-phase-nonrecv-autoref.rs:143:5
+   |
+LL |     i[i[3]] = i[4];
+   |     ^^^^^^^
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/cast/cast-macro-lhs.rs b/src/test/ui/cast/cast-macro-lhs.rs
new file mode 100644
index 00000000000..b509b3239bc
--- /dev/null
+++ b/src/test/ui/cast/cast-macro-lhs.rs
@@ -0,0 +1,12 @@
+// Test to make sure we suggest "consider casting" on the right span
+
+macro_rules! foo {
+    () => { 0 }
+}
+
+fn main() {
+    let x = foo!() as *const [u8];
+    //~^ ERROR cannot cast `usize` to a pointer that is wide
+    //~| NOTE creating a `*const [u8]` requires both an address and a length
+    //~| NOTE consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
+}
diff --git a/src/test/ui/cast/cast-macro-lhs.stderr b/src/test/ui/cast/cast-macro-lhs.stderr
new file mode 100644
index 00000000000..db7ce57e150
--- /dev/null
+++ b/src/test/ui/cast/cast-macro-lhs.stderr
@@ -0,0 +1,11 @@
+error[E0606]: cannot cast `usize` to a pointer that is wide
+  --> $DIR/cast-macro-lhs.rs:8:23
+   |
+LL |     let x = foo!() as *const [u8];
+   |             ------    ^^^^^^^^^^^ creating a `*const [u8]` requires both an address and a length
+   |             |
+   |             consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0606`.
diff --git a/src/test/ui/closures/old-closure-expression-remove-semicolon.fixed b/src/test/ui/closures/old-closure-expression-remove-semicolon.fixed
index 5629d4b6e6e..623e917da07 100644
--- a/src/test/ui/closures/old-closure-expression-remove-semicolon.fixed
+++ b/src/test/ui/closures/old-closure-expression-remove-semicolon.fixed
@@ -7,6 +7,6 @@ fn foo() -> i32 {
 fn main() {
     let _x: i32 = {
         //~^ ERROR mismatched types
-        foo() //~ HELP consider removing this semicolon
+        foo() //~ HELP remove this semicolon
     };
 }
diff --git a/src/test/ui/closures/old-closure-expression-remove-semicolon.rs b/src/test/ui/closures/old-closure-expression-remove-semicolon.rs
index 33f11b50afc..4974b086649 100644
--- a/src/test/ui/closures/old-closure-expression-remove-semicolon.rs
+++ b/src/test/ui/closures/old-closure-expression-remove-semicolon.rs
@@ -7,6 +7,6 @@ fn foo() -> i32 {
 fn main() {
     let _x: i32 = {
         //~^ ERROR mismatched types
-        foo(); //~ HELP consider removing this semicolon
+        foo(); //~ HELP remove this semicolon
     };
 }
diff --git a/src/test/ui/closures/old-closure-expression-remove-semicolon.stderr b/src/test/ui/closures/old-closure-expression-remove-semicolon.stderr
index ab7983dc9e4..9b73ce4fee3 100644
--- a/src/test/ui/closures/old-closure-expression-remove-semicolon.stderr
+++ b/src/test/ui/closures/old-closure-expression-remove-semicolon.stderr
@@ -5,7 +5,7 @@ LL |       let _x: i32 = {
    |  ___________________^
 LL | |
 LL | |         foo();
-   | |              - help: consider removing this semicolon
+   | |              - help: remove this semicolon
 LL | |     };
    | |_____^ expected `i32`, found `()`
 
diff --git a/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr b/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr
index df1fb58e25a..a4843bca58c 100644
--- a/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr
+++ b/src/test/ui/coercion/coercion-missing-tail-expected-type.stderr
@@ -6,7 +6,7 @@ LL | fn plus_one(x: i32) -> i32 {
    |    |
    |    implicitly returns `()` as its body has no tail or `return` expression
 LL |     x + 1;
-   |          - help: consider removing this semicolon
+   |          - help: remove this semicolon
 
 error[E0308]: mismatched types
   --> $DIR/coercion-missing-tail-expected-type.rs:8:13
@@ -16,7 +16,7 @@ LL | fn foo() -> Result<u8, u64> {
    |    |
    |    implicitly returns `()` as its body has no tail or `return` expression
 LL |     Ok(1);
-   |          - help: consider removing this semicolon
+   |          - help: remove this semicolon
    |
    = note:   expected enum `Result<u8, u64>`
            found unit type `()`
diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
index b1141cf3bdf..9f6c7ccf3fe 100644
--- a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
@@ -7,12 +7,5 @@ LL | fn test<const T: &'static dyn A>() {
    = note: the only supported types are integers, `bool` and `char`
    = help: more complex types are supported with `#![feature(adt_const_params)]`
 
-error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
-  --> $DIR/issue-63322-forbid-dyn.rs:9:18
-   |
-LL | fn test<const T: &'static dyn A>() {
-   |                  ^^^^^^^^^^^^^^ `&'static (dyn A + 'static)` doesn't derive both `PartialEq` and `Eq`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0741`.
diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs
index 01a6caa130f..116c3fcfb21 100644
--- a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs
+++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs
@@ -7,7 +7,7 @@ struct B;
 impl A for B {}
 
 fn test<const T: &'static dyn A>() {
-    //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` to be used
+    //[full]~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` to be used
     //[min]~^^ ERROR `&'static (dyn A + 'static)` is forbidden
     unimplemented!()
 }
diff --git a/src/test/ui/const-generics/nested-type.min.stderr b/src/test/ui/const-generics/nested-type.min.stderr
index 0e3c988ae4d..276ebf31ff8 100644
--- a/src/test/ui/const-generics/nested-type.min.stderr
+++ b/src/test/ui/const-generics/nested-type.min.stderr
@@ -14,14 +14,5 @@ LL | | }]>;
    = note: the only supported types are integers, `bool` and `char`
    = help: more complex types are supported with `#![feature(adt_const_params)]`
 
-error[E0015]: cannot call non-const fn `Foo::{constant#0}::Foo::<17_usize>::value` in constants
-  --> $DIR/nested-type.rs:15:5
-   |
-LL |     Foo::<17>::value()
-   |     ^^^^^^^^^^^^^^^^^^
-   |
-   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0015`.
diff --git a/src/test/ui/const-generics/nested-type.rs b/src/test/ui/const-generics/nested-type.rs
index 5240f5c3b0b..742340f430e 100644
--- a/src/test/ui/const-generics/nested-type.rs
+++ b/src/test/ui/const-generics/nested-type.rs
@@ -13,7 +13,7 @@ struct Foo<const N: [u8; { //[min]~ ERROR `[u8; _]` is forbidden
     }
 
     Foo::<17>::value()
-    //~^ ERROR cannot call non-const fn
+    //[full]~^ ERROR cannot call non-const fn
 }]>;
 
 fn main() {}
diff --git a/src/test/ui/consts/const-eval/ub-enum-overwrite.rs b/src/test/ui/consts/const-eval/ub-enum-overwrite.rs
new file mode 100644
index 00000000000..c5677849229
--- /dev/null
+++ b/src/test/ui/consts/const-eval/ub-enum-overwrite.rs
@@ -0,0 +1,17 @@
+#![feature(const_mut_refs)]
+
+enum E {
+    A(u8),
+    B,
+}
+
+const _: u8 = {
+    //~^ ERROR is undefined behavior
+    let mut e = E::A(1);
+    let p = if let E::A(x) = &mut e { x as *mut u8 } else { unreachable!() };
+    // Make sure overwriting `e` uninitializes other bytes
+    e = E::B;
+    unsafe { *p }
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/ub-enum-overwrite.stderr b/src/test/ui/consts/const-eval/ub-enum-overwrite.stderr
new file mode 100644
index 00000000000..88de7acb496
--- /dev/null
+++ b/src/test/ui/consts/const-eval/ub-enum-overwrite.stderr
@@ -0,0 +1,20 @@
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/ub-enum-overwrite.rs:8:1
+   |
+LL | / const _: u8 = {
+LL | |
+LL | |     let mut e = E::A(1);
+LL | |     let p = if let E::A(x) = &mut e { x as *mut u8 } else { unreachable!() };
+...  |
+LL | |     unsafe { *p }
+LL | | };
+   | |__^ type validation failed: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: 1, align: 1) {
+               __                                              │ ░
+           }
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/ub-enum.32bit.stderr b/src/test/ui/consts/const-eval/ub-enum.32bit.stderr
index 850acb52b0c..111d243959a 100644
--- a/src/test/ui/consts/const-eval/ub-enum.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-enum.32bit.stderr
@@ -79,11 +79,11 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:60:1
    |
 LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc29, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc30, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
-               ╾─alloc29─╼                                     │ ╾──╼
+               ╾─alloc30─╼                                     │ ╾──╼
            }
 
 error[E0080]: it is undefined behavior to use this value
diff --git a/src/test/ui/consts/const-eval/ub-enum.64bit.stderr b/src/test/ui/consts/const-eval/ub-enum.64bit.stderr
index 4f7dd5cdf7c..eee132bae00 100644
--- a/src/test/ui/consts/const-eval/ub-enum.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-enum.64bit.stderr
@@ -79,11 +79,11 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-enum.rs:60:1
    |
 LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { mem::transmute(&0) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc29, but expected initialized plain (non-pointer) bytes
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-tag>: encountered pointer to alloc30, but expected initialized plain (non-pointer) bytes
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
-               ╾───────alloc29───────╼                         │ ╾──────╼
+               ╾───────alloc30───────╼                         │ ╾──────╼
            }
 
 error[E0080]: it is undefined behavior to use this value
diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
index f6f2432f2d7..6f80da9cda9 100644
--- a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
@@ -145,11 +145,11 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:55:1
    |
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc41, but expected a function pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc43, but expected a function pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
-               ╾─alloc41─╼                                     │ ╾──╼
+               ╾─alloc43─╼                                     │ ╾──╼
            }
 
 error: aborting due to 14 previous errors
diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
index 28bd040e223..9b636761557 100644
--- a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
@@ -145,11 +145,11 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:55:1
    |
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc41, but expected a function pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc43, but expected a function pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
-               ╾───────alloc41───────╼                         │ ╾──────╼
+               ╾───────alloc43───────╼                         │ ╾──────╼
            }
 
 error: aborting due to 14 previous errors
diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr
index 4d60d4df203..293a2b47d30 100644
--- a/src/test/ui/consts/offset_from_ub.stderr
+++ b/src/test/ui/consts/offset_from_ub.stderr
@@ -40,19 +40,19 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:52:14
    |
 LL |     unsafe { ptr_offset_from(end_ptr, start_ptr) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc18 has size 4, so pointer at offset 10 is out-of-bounds
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc20 has size 4, so pointer at offset 10 is out-of-bounds
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:61:14
    |
 LL |     unsafe { ptr_offset_from(start_ptr, end_ptr) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc21 has size 4, so pointer at offset 10 is out-of-bounds
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc23 has size 4, so pointer at offset 10 is out-of-bounds
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:69:14
    |
 LL |     unsafe { ptr_offset_from(end_ptr, end_ptr) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc24 has size 4, so pointer at offset 10 is out-of-bounds
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc26 has size 4, so pointer at offset 10 is out-of-bounds
 
 error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/consts/std/alloc.32bit.stderr b/src/test/ui/consts/std/alloc.32bit.stderr
index 1490314a767..138eb69971c 100644
--- a/src/test/ui/consts/std/alloc.32bit.stderr
+++ b/src/test/ui/consts/std/alloc.32bit.stderr
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/alloc.rs:9:1
    |
 LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_.0.<enum-tag>: encountered 0x00000000, but expected a valid enum tag
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align.0.<enum-tag>: encountered 0x00000000, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/alloc.rs:13:1
    |
 LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_.0.<enum-tag>: encountered 0x00000003, but expected a valid enum tag
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align.0.<enum-tag>: encountered 0x00000003, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
diff --git a/src/test/ui/consts/std/alloc.64bit.stderr b/src/test/ui/consts/std/alloc.64bit.stderr
index 58349feec63..ecb08c39f3f 100644
--- a/src/test/ui/consts/std/alloc.64bit.stderr
+++ b/src/test/ui/consts/std/alloc.64bit.stderr
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/alloc.rs:9:1
    |
 LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_.0.<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align.0.<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -13,7 +13,7 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/alloc.rs:13:1
    |
 LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_.0.<enum-tag>: encountered 0x0000000000000003, but expected a valid enum tag
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align.0.<enum-tag>: encountered 0x0000000000000003, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
diff --git a/src/test/ui/error-codes/E0516.stderr b/src/test/ui/error-codes/E0516.stderr
index 2e6de5053d5..5243b7caf22 100644
--- a/src/test/ui/error-codes/E0516.stderr
+++ b/src/test/ui/error-codes/E0516.stderr
@@ -3,6 +3,11 @@ error[E0516]: `typeof` is a reserved keyword but unimplemented
    |
 LL |     let x: typeof(92) = 92;
    |            ^^^^^^^^^^ reserved keyword
+   |
+help: consider replacing `typeof(...)` with an actual type
+   |
+LL |     let x: i32 = 92;
+   |            ~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-29184.stderr b/src/test/ui/issues/issue-29184.stderr
index 87d3632ee42..75b6c64f2ce 100644
--- a/src/test/ui/issues/issue-29184.stderr
+++ b/src/test/ui/issues/issue-29184.stderr
@@ -3,6 +3,11 @@ error[E0516]: `typeof` is a reserved keyword but unimplemented
    |
 LL |     let x: typeof(92) = 92;
    |            ^^^^^^^^^^ reserved keyword
+   |
+help: consider replacing `typeof(...)` with an actual type
+   |
+LL |     let x: i32 = 92;
+   |            ~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-6458-4.stderr b/src/test/ui/issues/issue-6458-4.stderr
index 0cf82d37d5d..d6e74d10e03 100644
--- a/src/test/ui/issues/issue-6458-4.stderr
+++ b/src/test/ui/issues/issue-6458-4.stderr
@@ -6,7 +6,7 @@ LL | fn foo(b: bool) -> Result<bool,String> {
    |    |
    |    implicitly returns `()` as its body has no tail or `return` expression
 LL |     Err("bar".to_string());
-   |                           - help: consider removing this semicolon
+   |                           - help: remove this semicolon
    |
    = note:   expected enum `Result<bool, String>`
            found unit type `()`
diff --git a/src/test/ui/issues/issue-70093.rs b/src/test/ui/issues/issue-70093.rs
index fbe68fb9379..86459dc904a 100644
--- a/src/test/ui/issues/issue-70093.rs
+++ b/src/test/ui/issues/issue-70093.rs
@@ -2,6 +2,7 @@
 // compile-flags: -Zlink-native-libraries=no -Cdefault-linker-libraries=yes
 // ignore-windows - this will probably only work on unixish systems
 // ignore-fuchsia - missing __libc_start_main for some reason (#84733)
+// ignore-cross-compile - default-linker-libraries=yes doesn't play well with cross compiling
 
 #[link(name = "some-random-non-existent-library", kind = "static")]
 extern "C" {}
diff --git a/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr
index 489cb03ddd3..e7a6c1837bd 100644
--- a/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr
+++ b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr
@@ -9,7 +9,7 @@ note: the lint level is defined here
    |
 LL | #![deny(lossy_provenance_casts)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
-   = help: if you can't comply with strict provenance and need to expose the pointerprovenance you can use `.expose_addr()` instead
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
 
 error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
   --> $DIR/lint-strict-provenance-lossy-casts.rs:9:22
@@ -17,7 +17,7 @@ error: under strict provenance it is considered bad style to cast pointer `*cons
 LL |     let addr_32bit = &x as *const u8 as u32;
    |                      ^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr() as u32`
    |
-   = help: if you can't comply with strict provenance and need to expose the pointerprovenance you can use `.expose_addr()` instead
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/lint/unused/unused-attr-duplicate.rs b/src/test/ui/lint/unused/unused-attr-duplicate.rs
index 074d5a92ad6..692617eacfb 100644
--- a/src/test/ui/lint/unused/unused-attr-duplicate.rs
+++ b/src/test/ui/lint/unused/unused-attr-duplicate.rs
@@ -13,9 +13,6 @@
 #![crate_name = "unused_attr_duplicate"]
 #![crate_name = "unused_attr_duplicate2"] //~ ERROR unused attribute
 //~^ WARN this was previously accepted
-#![crate_type = "bin"]
-#![crate_type = "rlib"] //~ ERROR unused attribute
-//~^ WARN this was previously accepted
 #![recursion_limit = "128"]
 #![recursion_limit = "256"] //~ ERROR unused attribute
 //~^ WARN this was previously accepted
diff --git a/src/test/ui/lint/unused/unused-attr-duplicate.stderr b/src/test/ui/lint/unused/unused-attr-duplicate.stderr
index d4305add0aa..f592323b550 100644
--- a/src/test/ui/lint/unused/unused-attr-duplicate.stderr
+++ b/src/test/ui/lint/unused/unused-attr-duplicate.stderr
@@ -1,5 +1,5 @@
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:36:1
+  --> $DIR/unused-attr-duplicate.rs:33:1
    |
 LL | #[no_link]
    | ^^^^^^^^^^ help: remove this attribute
@@ -10,180 +10,180 @@ note: the lint level is defined here
 LL | #![deny(unused_attributes)]
    |         ^^^^^^^^^^^^^^^^^
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:35:1
+  --> $DIR/unused-attr-duplicate.rs:32:1
    |
 LL | #[no_link]
    | ^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:40:1
+  --> $DIR/unused-attr-duplicate.rs:37:1
    |
 LL | #[macro_use]
    | ^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:39:1
+  --> $DIR/unused-attr-duplicate.rs:36:1
    |
 LL | #[macro_use]
    | ^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:50:1
+  --> $DIR/unused-attr-duplicate.rs:47:1
    |
 LL | #[path = "bar.rs"]
    | ^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:49:1
+  --> $DIR/unused-attr-duplicate.rs:46:1
    |
 LL | #[path = "auxiliary/lint_unused_extern_crate.rs"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:56:1
+  --> $DIR/unused-attr-duplicate.rs:53:1
    |
 LL | #[ignore = "some text"]
    | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:55:1
+  --> $DIR/unused-attr-duplicate.rs:52:1
    |
 LL | #[ignore]
    | ^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:58:1
+  --> $DIR/unused-attr-duplicate.rs:55:1
    |
 LL | #[should_panic(expected = "values don't match")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:57:1
+  --> $DIR/unused-attr-duplicate.rs:54:1
    |
 LL | #[should_panic]
    | ^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:63:1
+  --> $DIR/unused-attr-duplicate.rs:60:1
    |
 LL | #[must_use = "some message"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:62:1
+  --> $DIR/unused-attr-duplicate.rs:59:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:69:1
+  --> $DIR/unused-attr-duplicate.rs:66:1
    |
 LL | #[non_exhaustive]
    | ^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:68:1
+  --> $DIR/unused-attr-duplicate.rs:65:1
    |
 LL | #[non_exhaustive]
    | ^^^^^^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:73:1
+  --> $DIR/unused-attr-duplicate.rs:70:1
    |
 LL | #[automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:72:1
+  --> $DIR/unused-attr-duplicate.rs:69:1
    |
 LL | #[automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:77:1
+  --> $DIR/unused-attr-duplicate.rs:74:1
    |
 LL | #[inline(never)]
    | ^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:76:1
+  --> $DIR/unused-attr-duplicate.rs:73:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:80:1
+  --> $DIR/unused-attr-duplicate.rs:77:1
    |
 LL | #[cold]
    | ^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:79:1
+  --> $DIR/unused-attr-duplicate.rs:76:1
    |
 LL | #[cold]
    | ^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:82:1
+  --> $DIR/unused-attr-duplicate.rs:79:1
    |
 LL | #[track_caller]
    | ^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:81:1
+  --> $DIR/unused-attr-duplicate.rs:78:1
    |
 LL | #[track_caller]
    | ^^^^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:95:1
+  --> $DIR/unused-attr-duplicate.rs:92:1
    |
 LL | #[export_name = "exported_symbol_name"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:97:1
+  --> $DIR/unused-attr-duplicate.rs:94:1
    |
 LL | #[export_name = "exported_symbol_name2"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:101:1
+  --> $DIR/unused-attr-duplicate.rs:98:1
    |
 LL | #[no_mangle]
    | ^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:100:1
+  --> $DIR/unused-attr-duplicate.rs:97:1
    |
 LL | #[no_mangle]
    | ^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:105:1
+  --> $DIR/unused-attr-duplicate.rs:102:1
    |
 LL | #[used]
    | ^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:104:1
+  --> $DIR/unused-attr-duplicate.rs:101:1
    |
 LL | #[used]
    | ^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:89:5
+  --> $DIR/unused-attr-duplicate.rs:86:5
    |
 LL |     #[link_name = "this_does_not_exist"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:91:5
+  --> $DIR/unused-attr-duplicate.rs:88:5
    |
 LL |     #[link_name = "rust_dbg_extern_identity_u32"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -205,102 +205,89 @@ LL | #![crate_name = "unused_attr_duplicate"]
 error: unused attribute
   --> $DIR/unused-attr-duplicate.rs:17:1
    |
-LL | #![crate_type = "rlib"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
-   |
-note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:16:1
-   |
-LL | #![crate_type = "bin"]
-   | ^^^^^^^^^^^^^^^^^^^^^^
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:20:1
-   |
 LL | #![recursion_limit = "256"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:19:1
+  --> $DIR/unused-attr-duplicate.rs:16:1
    |
 LL | #![recursion_limit = "128"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:23:1
+  --> $DIR/unused-attr-duplicate.rs:20:1
    |
 LL | #![type_length_limit = "1"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:22:1
+  --> $DIR/unused-attr-duplicate.rs:19:1
    |
 LL | #![type_length_limit = "1048576"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:26:1
+  --> $DIR/unused-attr-duplicate.rs:23:1
    |
 LL | #![no_std]
    | ^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:25:1
+  --> $DIR/unused-attr-duplicate.rs:22:1
    |
 LL | #![no_std]
    | ^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:28:1
+  --> $DIR/unused-attr-duplicate.rs:25:1
    |
 LL | #![no_implicit_prelude]
    | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:27:1
+  --> $DIR/unused-attr-duplicate.rs:24:1
    |
 LL | #![no_implicit_prelude]
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:30:1
+  --> $DIR/unused-attr-duplicate.rs:27:1
    |
 LL | #![windows_subsystem = "windows"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:29:1
+  --> $DIR/unused-attr-duplicate.rs:26:1
    |
 LL | #![windows_subsystem = "console"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:33:1
+  --> $DIR/unused-attr-duplicate.rs:30:1
    |
 LL | #![no_builtins]
    | ^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:32:1
+  --> $DIR/unused-attr-duplicate.rs:29:1
    |
 LL | #![no_builtins]
    | ^^^^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:43:5
+  --> $DIR/unused-attr-duplicate.rs:40:5
    |
 LL |     #[macro_export]
    |     ^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:42:5
+  --> $DIR/unused-attr-duplicate.rs:39:5
    |
 LL |     #[macro_export]
    |     ^^^^^^^^^^^^^^^
 
-error: aborting due to 24 previous errors
+error: aborting due to 23 previous errors
 
diff --git a/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr b/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr
index 0b33d8d0a2b..82d136bd318 100644
--- a/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr
+++ b/src/test/ui/liveness/liveness-return-last-stmt-semi.stderr
@@ -14,7 +14,7 @@ LL | fn bar(x: u32) -> u32 {
    |    |
    |    implicitly returns `()` as its body has no tail or `return` expression
 LL |     x * 2;
-   |          - help: consider removing this semicolon
+   |          - help: remove this semicolon
 
 error[E0308]: mismatched types
   --> $DIR/liveness-return-last-stmt-semi.rs:13:19
diff --git a/src/test/ui/privacy/restricted/relative-2018.rs b/src/test/ui/privacy/restricted/relative-2018.rs
index 69b7c1e4d4f..954169a9ffb 100644
--- a/src/test/ui/privacy/restricted/relative-2018.rs
+++ b/src/test/ui/privacy/restricted/relative-2018.rs
@@ -7,7 +7,7 @@ mod m {
     pub(in ::core) struct S4;
     //~^ ERROR visibilities can only be restricted to ancestor modules
     pub(in a::b) struct S5;
-    //~^ ERROR relative paths are not supported in visibilities on 2018 edition
+    //~^ ERROR relative paths are not supported in visibilities in 2018 edition or later
 }
 
 fn main() {}
diff --git a/src/test/ui/privacy/restricted/relative-2018.stderr b/src/test/ui/privacy/restricted/relative-2018.stderr
index 54fee085ee9..dec0d5157da 100644
--- a/src/test/ui/privacy/restricted/relative-2018.stderr
+++ b/src/test/ui/privacy/restricted/relative-2018.stderr
@@ -4,7 +4,7 @@ error[E0742]: visibilities can only be restricted to ancestor modules
 LL |     pub(in ::core) struct S4;
    |            ^^^^^^
 
-error: relative paths are not supported in visibilities on 2018 edition
+error: relative paths are not supported in visibilities in 2018 edition or later
   --> $DIR/relative-2018.rs:9:12
    |
 LL |     pub(in a::b) struct S5;
diff --git a/src/test/ui/ptr_ops/issue-80309-safe.rs b/src/test/ui/ptr_ops/issue-80309-safe.rs
index ca3778aab2d..f7513b6b8f4 100644
--- a/src/test/ui/ptr_ops/issue-80309-safe.rs
+++ b/src/test/ui/ptr_ops/issue-80309-safe.rs
@@ -1,6 +1,6 @@
 // run-pass
 // min-llvm-version: 13.0
-// compiler-flags: -O
+// compile-flags: -O
 
 // Regression test for issue #80309
 
diff --git a/src/test/ui/ptr_ops/issue-80309.rs b/src/test/ui/ptr_ops/issue-80309.rs
index bbec1012082..5c0f4b76ceb 100644
--- a/src/test/ui/ptr_ops/issue-80309.rs
+++ b/src/test/ui/ptr_ops/issue-80309.rs
@@ -1,6 +1,6 @@
 // run-pass
 // min-llvm-version: 13.0
-// compiler-flags: -O
+// compile-flags: -O
 
 // Regression test for issue #80309
 
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
index 5b2693d07a7..1bd8b74240e 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
@@ -25,6 +25,67 @@ use std::ops::Range;
 
 fn main() {}
 
+fn _if() {
+    if (let 0 = 1) {}
+    //~^ ERROR `let` expressions are not supported here
+
+    if (((let 0 = 1))) {}
+    //~^ ERROR `let` expressions are not supported here
+
+    if (let 0 = 1) && true {}
+    //~^ ERROR `let` expressions are not supported here
+
+    if true && (let 0 = 1) {}
+    //~^ ERROR `let` expressions are not supported here
+
+    if (let 0 = 1) && (let 0 = 1) {}
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR `let` expressions are not supported here
+
+    if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR `let` expressions are not supported here
+    //~| ERROR `let` expressions are not supported here
+}
+
+fn _while() {
+    while (let 0 = 1) {}
+    //~^ ERROR `let` expressions are not supported here
+
+    while (((let 0 = 1))) {}
+    //~^ ERROR `let` expressions are not supported here
+
+    while (let 0 = 1) && true {}
+    //~^ ERROR `let` expressions are not supported here
+
+    while true && (let 0 = 1) {}
+    //~^ ERROR `let` expressions are not supported here
+
+    while (let 0 = 1) && (let 0 = 1) {}
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR `let` expressions are not supported here
+
+    while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR `let` expressions are not supported here
+    //~| ERROR `let` expressions are not supported here
+}
+
+fn _macros() {
+    macro_rules! use_expr {
+        ($e:expr) => {
+            if $e {}
+            while $e {}
+        }
+    }
+    use_expr!((let 0 = 1 && 0 == 0));
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR `let` expressions are not supported here
+    use_expr!((let 0 = 1));
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR `let` expressions are not supported here
+}
+
 fn nested_within_if_expr() {
     if &let 0 = 0 {} //~ ERROR `let` expressions are not supported here
     //~^ ERROR mismatched types
@@ -234,3 +295,44 @@ fn inside_const_generic_arguments() {
         //~| ERROR  expressions must be enclosed in braces
     >::O == 5 {}
 }
+
+fn with_parenthesis() {
+    let opt = Some(Some(1i32));
+
+    if (let Some(a) = opt && true) {
+    //~^ ERROR `let` expressions are not supported here
+    }
+
+    if (let Some(a) = opt) && true {
+    //~^ ERROR `let` expressions are not supported here
+    }
+    if (let Some(a) = opt) && (let Some(b) = a) {
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR `let` expressions are not supported here
+    }
+    if let Some(a) = opt && (true && true) {
+    }
+
+    if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR `let` expressions are not supported here
+    }
+    if (let Some(a) = opt && (let Some(b) = a)) && true {
+    //~^ ERROR `let` expressions are not supported here
+    //~| ERROR `let` expressions are not supported here
+    }
+    if (let Some(a) = opt && (true)) && true {
+    //~^ ERROR `let` expressions are not supported here
+    }
+
+    if (true && (true)) && let Some(a) = opt {
+    }
+    if (true) && let Some(a) = opt {
+    }
+    if true && let Some(a) = opt {
+    }
+
+    let fun = || true;
+    if let true = (true && fun()) && (true) {
+    }
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
index 34f059248b6..00da9d26057 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -1,5 +1,5 @@
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/disallowed-positions.rs:232:9
+  --> $DIR/disallowed-positions.rs:293:9
    |
 LL |         true && let 1 = 1
    |         ^^^^^^^^^^^^^^^^^
@@ -12,555 +12,968 @@ LL |         { true && let 1 = 1 }
 error: `let` expressions are not supported here
   --> $DIR/disallowed-positions.rs:29:9
    |
+LL |     if (let 0 = 1) {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:29:9
+   |
+LL |     if (let 0 = 1) {}
+   |         ^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:32:11
+   |
+LL |     if (((let 0 = 1))) {}
+   |           ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:32:11
+   |
+LL |     if (((let 0 = 1))) {}
+   |           ^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:35:9
+   |
+LL |     if (let 0 = 1) && true {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:35:9
+   |
+LL |     if (let 0 = 1) && true {}
+   |         ^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:38:17
+   |
+LL |     if true && (let 0 = 1) {}
+   |                 ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:38:17
+   |
+LL |     if true && (let 0 = 1) {}
+   |                 ^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:41:9
+   |
+LL |     if (let 0 = 1) && (let 0 = 1) {}
+   |         ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:41:9
+   |
+LL |     if (let 0 = 1) && (let 0 = 1) {}
+   |         ^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:41:24
+   |
+LL |     if (let 0 = 1) && (let 0 = 1) {}
+   |                        ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:41:24
+   |
+LL |     if (let 0 = 1) && (let 0 = 1) {}
+   |                        ^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:45:35
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                   ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:45:35
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:45:48
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:45:35
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:45:61
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                             ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:45:35
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:52:12
+   |
+LL |     while (let 0 = 1) {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:52:12
+   |
+LL |     while (let 0 = 1) {}
+   |            ^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:55:14
+   |
+LL |     while (((let 0 = 1))) {}
+   |              ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:55:14
+   |
+LL |     while (((let 0 = 1))) {}
+   |              ^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:58:12
+   |
+LL |     while (let 0 = 1) && true {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:58:12
+   |
+LL |     while (let 0 = 1) && true {}
+   |            ^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:61:20
+   |
+LL |     while true && (let 0 = 1) {}
+   |                    ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:61:20
+   |
+LL |     while true && (let 0 = 1) {}
+   |                    ^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:64:12
+   |
+LL |     while (let 0 = 1) && (let 0 = 1) {}
+   |            ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:64:12
+   |
+LL |     while (let 0 = 1) && (let 0 = 1) {}
+   |            ^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:64:27
+   |
+LL |     while (let 0 = 1) && (let 0 = 1) {}
+   |                           ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:64:27
+   |
+LL |     while (let 0 = 1) && (let 0 = 1) {}
+   |                           ^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:68:38
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                      ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:68:38
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:68:51
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                   ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:68:38
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:68:64
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                                ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:68:38
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:81:16
+   |
+LL |     use_expr!((let 0 = 1 && 0 == 0));
+   |                ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:81:16
+   |
+LL |     use_expr!((let 0 = 1 && 0 == 0));
+   |                ^^^^^^^^^^^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:81:16
+   |
+LL |     use_expr!((let 0 = 1 && 0 == 0));
+   |                ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:81:16
+   |
+LL |     use_expr!((let 0 = 1 && 0 == 0));
+   |                ^^^^^^^^^^^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:84:16
+   |
+LL |     use_expr!((let 0 = 1));
+   |                ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:84:16
+   |
+LL |     use_expr!((let 0 = 1));
+   |                ^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:84:16
+   |
+LL |     use_expr!((let 0 = 1));
+   |                ^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:84:16
+   |
+LL |     use_expr!((let 0 = 1));
+   |                ^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:90:9
+   |
 LL |     if &let 0 = 0 {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:32:9
+  --> $DIR/disallowed-positions.rs:93:9
    |
 LL |     if !let 0 = 0 {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:33:9
+  --> $DIR/disallowed-positions.rs:94:9
    |
 LL |     if *let 0 = 0 {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:35:9
+  --> $DIR/disallowed-positions.rs:96:9
    |
 LL |     if -let 0 = 0 {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:43:9
+  --> $DIR/disallowed-positions.rs:104:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:104:9
+   |
+LL |     if (let 0 = 0)? {}
+   |         ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:47:16
+  --> $DIR/disallowed-positions.rs:108:16
    |
 LL |     if true || let 0 = 0 {}
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
-note: `||` operators are not currently supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:47:13
+note: `||` operators are not supported in let chain expressions
+  --> $DIR/disallowed-positions.rs:108:13
    |
 LL |     if true || let 0 = 0 {}
    |             ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:48:17
+  --> $DIR/disallowed-positions.rs:109:17
    |
 LL |     if (true || let 0 = 0) {}
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
-note: `||` operators are not currently supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:48:14
+note: `||` operators are not supported in let chain expressions
+  --> $DIR/disallowed-positions.rs:109:14
    |
 LL |     if (true || let 0 = 0) {}
    |              ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:49:25
+  --> $DIR/disallowed-positions.rs:110:25
    |
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
-note: `||` operators are not currently supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:49:22
+note: `||` operators are not supported in let chain expressions
+  --> $DIR/disallowed-positions.rs:110:22
    |
 LL |     if true && (true || let 0 = 0) {}
    |                      ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:50:25
+  --> $DIR/disallowed-positions.rs:111:25
    |
 LL |     if true || (true && let 0 = 0) {}
    |                         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
-note: `||` operators are not currently supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:50:13
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:111:17
    |
 LL |     if true || (true && let 0 = 0) {}
-   |             ^^
+   |                 ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:53:12
+  --> $DIR/disallowed-positions.rs:114:12
    |
 LL |     if x = let 0 = 0 {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:56:15
+  --> $DIR/disallowed-positions.rs:117:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:117:15
+   |
+LL |     if true..(let 0 = 0) {}
+   |               ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:58:11
+  --> $DIR/disallowed-positions.rs:119:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:119:11
+   |
+LL |     if ..(let 0 = 0) {}
+   |           ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:60:9
+  --> $DIR/disallowed-positions.rs:121:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:121:9
+   |
+LL |     if (let 0 = 0).. {}
+   |         ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:64:8
+  --> $DIR/disallowed-positions.rs:125:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:68:8
+  --> $DIR/disallowed-positions.rs:129:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:75:8
+  --> $DIR/disallowed-positions.rs:136:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:83:8
+  --> $DIR/disallowed-positions.rs:144:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:89:19
+  --> $DIR/disallowed-positions.rs:150:19
    |
 LL |     if let true = let true = true {}
    |                   ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:93:12
+  --> $DIR/disallowed-positions.rs:154:12
    |
 LL |     while &let 0 = 0 {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:96:12
+  --> $DIR/disallowed-positions.rs:157:12
    |
 LL |     while !let 0 = 0 {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:97:12
+  --> $DIR/disallowed-positions.rs:158:12
    |
 LL |     while *let 0 = 0 {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:99:12
+  --> $DIR/disallowed-positions.rs:160:12
    |
 LL |     while -let 0 = 0 {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:107:12
+  --> $DIR/disallowed-positions.rs:168:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:168:12
+   |
+LL |     while (let 0 = 0)? {}
+   |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:111:19
+  --> $DIR/disallowed-positions.rs:172:19
    |
 LL |     while true || let 0 = 0 {}
    |                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
-note: `||` operators are not currently supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:111:16
+note: `||` operators are not supported in let chain expressions
+  --> $DIR/disallowed-positions.rs:172:16
    |
 LL |     while true || let 0 = 0 {}
    |                ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:112:20
+  --> $DIR/disallowed-positions.rs:173:20
    |
 LL |     while (true || let 0 = 0) {}
    |                    ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
-note: `||` operators are not currently supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:112:17
+note: `||` operators are not supported in let chain expressions
+  --> $DIR/disallowed-positions.rs:173:17
    |
 LL |     while (true || let 0 = 0) {}
    |                 ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:113:28
+  --> $DIR/disallowed-positions.rs:174:28
    |
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
-note: `||` operators are not currently supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:113:25
+note: `||` operators are not supported in let chain expressions
+  --> $DIR/disallowed-positions.rs:174:25
    |
 LL |     while true && (true || let 0 = 0) {}
    |                         ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:114:28
+  --> $DIR/disallowed-positions.rs:175:28
    |
 LL |     while true || (true && let 0 = 0) {}
    |                            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
-note: `||` operators are not currently supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:114:16
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:175:20
    |
 LL |     while true || (true && let 0 = 0) {}
-   |                ^^
+   |                    ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:117:15
+  --> $DIR/disallowed-positions.rs:178:15
    |
 LL |     while x = let 0 = 0 {}
    |               ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:120:18
+  --> $DIR/disallowed-positions.rs:181:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:181:18
+   |
+LL |     while true..(let 0 = 0) {}
+   |                  ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:122:14
+  --> $DIR/disallowed-positions.rs:183:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:183:14
+   |
+LL |     while ..(let 0 = 0) {}
+   |              ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:124:12
+  --> $DIR/disallowed-positions.rs:185:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:185:12
+   |
+LL |     while (let 0 = 0).. {}
+   |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:128:11
+  --> $DIR/disallowed-positions.rs:189:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:132:11
+  --> $DIR/disallowed-positions.rs:193:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:139:11
+  --> $DIR/disallowed-positions.rs:200:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:147:11
+  --> $DIR/disallowed-positions.rs:208:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:153:22
+  --> $DIR/disallowed-positions.rs:214:22
    |
 LL |     while let true = let true = true {}
    |                      ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:167:6
+  --> $DIR/disallowed-positions.rs:228:6
    |
 LL |     &let 0 = 0;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:169:6
+  --> $DIR/disallowed-positions.rs:230:6
    |
 LL |     !let 0 = 0;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:170:6
+  --> $DIR/disallowed-positions.rs:231:6
    |
 LL |     *let 0 = 0;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:172:6
+  --> $DIR/disallowed-positions.rs:233:6
    |
 LL |     -let 0 = 0;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:180:6
+  --> $DIR/disallowed-positions.rs:241:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:241:6
+   |
+LL |     (let 0 = 0)?;
+   |      ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:184:13
+  --> $DIR/disallowed-positions.rs:245:13
    |
 LL |     true || let 0 = 0;
    |             ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
-note: `||` operators are not currently supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:184:10
+note: `||` operators are not supported in let chain expressions
+  --> $DIR/disallowed-positions.rs:245:10
    |
 LL |     true || let 0 = 0;
    |          ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:185:14
+  --> $DIR/disallowed-positions.rs:246:14
    |
 LL |     (true || let 0 = 0);
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
-note: `||` operators are not currently supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:185:11
+note: `||` operators are not supported in let chain expressions
+  --> $DIR/disallowed-positions.rs:246:11
    |
 LL |     (true || let 0 = 0);
    |           ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:186:22
+  --> $DIR/disallowed-positions.rs:247:22
    |
 LL |     true && (true || let 0 = 0);
    |                      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
-note: `||` operators are not currently supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:186:19
+note: `||` operators are not supported in let chain expressions
+  --> $DIR/disallowed-positions.rs:247:19
    |
 LL |     true && (true || let 0 = 0);
    |                   ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:189:9
+  --> $DIR/disallowed-positions.rs:250:9
    |
 LL |     x = let 0 = 0;
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:191:12
+  --> $DIR/disallowed-positions.rs:252:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:252:12
+   |
+LL |     true..(let 0 = 0);
+   |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:192:8
+  --> $DIR/disallowed-positions.rs:253:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:253:8
+   |
+LL |     ..(let 0 = 0);
+   |        ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:193:6
+  --> $DIR/disallowed-positions.rs:254:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:254:6
+   |
+LL |     (let 0 = 0)..;
+   |      ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:195:6
+  --> $DIR/disallowed-positions.rs:256:6
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:199:6
+  --> $DIR/disallowed-positions.rs:260:6
    |
 LL |     (let true = let true = true);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:260:6
+   |
+LL |     (let true = let true = true);
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:203:6
+  --> $DIR/disallowed-positions.rs:264:6
    |
 LL |     &let 0 = 0
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:214:17
+  --> $DIR/disallowed-positions.rs:275:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:218:17
+  --> $DIR/disallowed-positions.rs:279:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:222:17
+  --> $DIR/disallowed-positions.rs:283:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:232:17
+  --> $DIR/disallowed-positions.rs:293:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:302:9
+   |
+LL |     if (let Some(a) = opt && true) {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:302:9
+   |
+LL |     if (let Some(a) = opt && true) {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:306:9
+   |
+LL |     if (let Some(a) = opt) && true {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:306:9
+   |
+LL |     if (let Some(a) = opt) && true {
+   |         ^^^^^^^^^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:309:9
+   |
+LL |     if (let Some(a) = opt) && (let Some(b) = a) {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:309:9
+   |
+LL |     if (let Some(a) = opt) && (let Some(b) = a) {
+   |         ^^^^^^^^^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:309:32
+   |
+LL |     if (let Some(a) = opt) && (let Some(b) = a) {
+   |                                ^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:309:32
+   |
+LL |     if (let Some(a) = opt) && (let Some(b) = a) {
+   |                                ^^^^^^^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:316:9
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:316:9
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:316:31
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
+   |                               ^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:316:31
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
+   |                               ^^^^^^^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:320:9
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:320:9
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:320:31
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
+   |                               ^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:320:31
+   |
+LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
+   |                               ^^^^^^^^^^^^^^^
+
+error: `let` expressions are not supported here
+  --> $DIR/disallowed-positions.rs:324:9
+   |
+LL |     if (let Some(a) = opt && (true)) && true {
+   |         ^^^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+note: `let`s wrapped in parentheses are not supported in a context with let chains
+  --> $DIR/disallowed-positions.rs:324:9
+   |
+LL |     if (let Some(a) = opt && (true)) && true {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:29:8
+  --> $DIR/disallowed-positions.rs:90:8
    |
 LL |     if &let 0 = 0 {}
    |        ^^^^^^^^^^ expected `bool`, found `&bool`
@@ -572,19 +985,19 @@ LL +     if let 0 = 0 {}
    | 
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:33:8
+  --> $DIR/disallowed-positions.rs:94:8
    |
 LL |     if *let 0 = 0 {}
    |        ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:35:8
+  --> $DIR/disallowed-positions.rs:96:8
    |
 LL |     if -let 0 = 0 {}
    |        ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:43:8
+  --> $DIR/disallowed-positions.rs:104:8
    |
 LL |     if (let 0 = 0)? {}
    |        ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -592,7 +1005,7 @@ LL |     if (let 0 = 0)? {}
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:43:19
+  --> $DIR/disallowed-positions.rs:104:19
    |
 LL | / fn nested_within_if_expr() {
 LL | |     if &let 0 = 0 {}
@@ -609,7 +1022,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:53:8
+  --> $DIR/disallowed-positions.rs:114:8
    |
 LL |     if x = let 0 = 0 {}
    |        ^^^^^^^^^^^^^ expected `bool`, found `()`
@@ -620,7 +1033,7 @@ LL |     if x == let 0 = 0 {}
    |          ~~
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:56:8
+  --> $DIR/disallowed-positions.rs:117:8
    |
 LL |     if true..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -629,7 +1042,7 @@ LL |     if true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:58:8
+  --> $DIR/disallowed-positions.rs:119:8
    |
 LL |     if ..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
@@ -638,7 +1051,7 @@ LL |     if ..(let 0 = 0) {}
             found struct `RangeTo<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:60:8
+  --> $DIR/disallowed-positions.rs:121:8
    |
 LL |     if (let 0 = 0).. {}
    |        ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
@@ -647,7 +1060,7 @@ LL |     if (let 0 = 0).. {}
             found struct `RangeFrom<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:64:12
+  --> $DIR/disallowed-positions.rs:125:12
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -658,7 +1071,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:64:8
+  --> $DIR/disallowed-positions.rs:125:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -667,7 +1080,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:68:12
+  --> $DIR/disallowed-positions.rs:129:12
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -678,7 +1091,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:68:8
+  --> $DIR/disallowed-positions.rs:129:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -687,7 +1100,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:75:12
+  --> $DIR/disallowed-positions.rs:136:12
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -698,16 +1111,16 @@ LL |     if let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:75:41
+  --> $DIR/disallowed-positions.rs:136:41
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |                                         ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:75:41: 75:48]`
+           found closure `[closure@$DIR/disallowed-positions.rs:136:41: 136:48]`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:75:8
+  --> $DIR/disallowed-positions.rs:136:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -716,7 +1129,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:83:12
+  --> $DIR/disallowed-positions.rs:144:12
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -727,7 +1140,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:83:44
+  --> $DIR/disallowed-positions.rs:144:44
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |                                            ^^^^^^^ expected `bool`, found `&&bool`
@@ -739,7 +1152,7 @@ LL +     if let Range { start: true, end } = t..false {}
    | 
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:83:8
+  --> $DIR/disallowed-positions.rs:144:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -748,7 +1161,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<bool>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:39:20
+  --> $DIR/disallowed-positions.rs:100:20
    |
 LL |         if let 0 = 0? {}
    |                    ^^ the `?` operator cannot be applied to type `{integer}`
@@ -756,7 +1169,7 @@ LL |         if let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:93:11
+  --> $DIR/disallowed-positions.rs:154:11
    |
 LL |     while &let 0 = 0 {}
    |           ^^^^^^^^^^ expected `bool`, found `&bool`
@@ -768,19 +1181,19 @@ LL +     while let 0 = 0 {}
    | 
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:97:11
+  --> $DIR/disallowed-positions.rs:158:11
    |
 LL |     while *let 0 = 0 {}
    |           ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:99:11
+  --> $DIR/disallowed-positions.rs:160:11
    |
 LL |     while -let 0 = 0 {}
    |           ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:107:11
+  --> $DIR/disallowed-positions.rs:168:11
    |
 LL |     while (let 0 = 0)? {}
    |           ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -788,7 +1201,7 @@ LL |     while (let 0 = 0)? {}
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:107:22
+  --> $DIR/disallowed-positions.rs:168:22
    |
 LL | / fn nested_within_while_expr() {
 LL | |     while &let 0 = 0 {}
@@ -805,7 +1218,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:117:11
+  --> $DIR/disallowed-positions.rs:178:11
    |
 LL |     while x = let 0 = 0 {}
    |           ^^^^^^^^^^^^^ expected `bool`, found `()`
@@ -816,7 +1229,7 @@ LL |     while x == let 0 = 0 {}
    |             ~~
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:120:11
+  --> $DIR/disallowed-positions.rs:181:11
    |
 LL |     while true..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -825,7 +1238,7 @@ LL |     while true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:122:11
+  --> $DIR/disallowed-positions.rs:183:11
    |
 LL |     while ..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
@@ -834,7 +1247,7 @@ LL |     while ..(let 0 = 0) {}
             found struct `RangeTo<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:124:11
+  --> $DIR/disallowed-positions.rs:185:11
    |
 LL |     while (let 0 = 0).. {}
    |           ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
@@ -843,7 +1256,7 @@ LL |     while (let 0 = 0).. {}
             found struct `RangeFrom<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:128:15
+  --> $DIR/disallowed-positions.rs:189:15
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -854,7 +1267,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:128:11
+  --> $DIR/disallowed-positions.rs:189:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -863,7 +1276,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:132:15
+  --> $DIR/disallowed-positions.rs:193:15
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -874,7 +1287,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:132:11
+  --> $DIR/disallowed-positions.rs:193:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -883,7 +1296,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:139:15
+  --> $DIR/disallowed-positions.rs:200:15
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -894,16 +1307,16 @@ LL |     while let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:139:44
+  --> $DIR/disallowed-positions.rs:200:44
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |                                            ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:139:44: 139:51]`
+           found closure `[closure@$DIR/disallowed-positions.rs:200:44: 200:51]`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:139:11
+  --> $DIR/disallowed-positions.rs:200:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -912,7 +1325,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:147:15
+  --> $DIR/disallowed-positions.rs:208:15
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -923,7 +1336,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:147:47
+  --> $DIR/disallowed-positions.rs:208:47
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |                                               ^^^^^^^ expected `bool`, found `&&bool`
@@ -935,7 +1348,7 @@ LL +     while let Range { start: true, end } = t..false {}
    | 
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:147:11
+  --> $DIR/disallowed-positions.rs:208:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -944,7 +1357,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<bool>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:103:23
+  --> $DIR/disallowed-positions.rs:164:23
    |
 LL |         while let 0 = 0? {}
    |                       ^^ the `?` operator cannot be applied to type `{integer}`
@@ -952,19 +1365,19 @@ LL |         while let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:170:5
+  --> $DIR/disallowed-positions.rs:231:5
    |
 LL |     *let 0 = 0;
    |     ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:172:5
+  --> $DIR/disallowed-positions.rs:233:5
    |
 LL |     -let 0 = 0;
    |     ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:180:5
+  --> $DIR/disallowed-positions.rs:241:5
    |
 LL |     (let 0 = 0)?;
    |     ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -972,7 +1385,7 @@ LL |     (let 0 = 0)?;
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:180:16
+  --> $DIR/disallowed-positions.rs:241:16
    |
 LL | / fn outside_if_and_while_expr() {
 LL | |     &let 0 = 0;
@@ -989,7 +1402,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:195:10
+  --> $DIR/disallowed-positions.rs:256:10
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1000,7 +1413,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:203:5
+  --> $DIR/disallowed-positions.rs:264:5
    |
 LL | fn outside_if_and_while_expr() {
    |                                - help: try adding a return type: `-> &bool`
@@ -1009,14 +1422,14 @@ LL |     &let 0 = 0
    |     ^^^^^^^^^^ expected `()`, found `&bool`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:176:17
+  --> $DIR/disallowed-positions.rs:237:17
    |
 LL |         let 0 = 0?;
    |                 ^^ the `?` operator cannot be applied to type `{integer}`
    |
    = help: the trait `Try` is not implemented for `{integer}`
 
-error: aborting due to 103 previous errors
+error: aborting due to 134 previous errors
 
 Some errors have detailed explanations: E0277, E0308, E0600, E0614.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr b/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr
index 992c34eb402..aebfc1a72b7 100644
--- a/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.stderr
@@ -72,7 +72,6 @@ LL |     let Some(n) = opt && let another = n else {
    |                          ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
-   = note: as well as when nested within `&&` and parentheses in those conditions
 
 error[E0308]: mismatched types
   --> $DIR/ensure-that-let-else-does-not-interact-with-let-chains.rs:9:19
diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
index 53fec8316e7..ac60bc7e57f 100644
--- a/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
@@ -11,35 +11,12 @@ use std::ops::Range;
 fn _if() {
     if let 0 = 1 {} // Stable!
 
-    if (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
-
-    if (((let 0 = 1))) {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
-
     if true && let 0 = 1 {}
     //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if let 0 = 1 && true {}
     //~^ ERROR `let` expressions in this position are unstable [E0658]
 
-    if (let 0 = 1) && true {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
-
-    if true && (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
-
-    if (let 0 = 1) && (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
-    //~| ERROR `let` expressions in this position are unstable [E0658]
-
-    if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
-    //~| ERROR `let` expressions in this position are unstable [E0658]
-    //~| ERROR `let` expressions in this position are unstable [E0658]
-    //~| ERROR `let` expressions in this position are unstable [E0658]
-    //~| ERROR `let` expressions in this position are unstable [E0658]
-
     if let Range { start: _, end: _ } = (true..true) && false {}
     //~^ ERROR `let` expressions in this position are unstable [E0658]
 }
@@ -47,35 +24,12 @@ fn _if() {
 fn _while() {
     while let 0 = 1 {} // Stable!
 
-    while (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
-
-    while (((let 0 = 1))) {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
-
     while true && let 0 = 1 {}
     //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while let 0 = 1 && true {}
     //~^ ERROR `let` expressions in this position are unstable [E0658]
 
-    while (let 0 = 1) && true {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
-
-    while true && (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
-
-    while (let 0 = 1) && (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
-    //~| ERROR `let` expressions in this position are unstable [E0658]
-
-    while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
-    //~| ERROR `let` expressions in this position are unstable [E0658]
-    //~| ERROR `let` expressions in this position are unstable [E0658]
-    //~| ERROR `let` expressions in this position are unstable [E0658]
-    //~| ERROR `let` expressions in this position are unstable [E0658]
-
     while let Range { start: _, end: _ } = (true..true) && false {}
     //~^ ERROR `let` expressions in this position are unstable [E0658]
 }
@@ -92,10 +46,6 @@ fn _macros() {
             while $e {}
         }
     }
-    use_expr!((let 0 = 1 && 0 == 0));
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
-    use_expr!((let 0 = 1));
-    //~^ ERROR `let` expressions in this position are unstable [E0658]
     #[cfg(FALSE)] (let 0 = 1);
     //~^ ERROR `let` expressions in this position are unstable [E0658]
     use_expr!(let 0 = 1);
diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
index 458826498fe..1eabee47c64 100644
--- a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
@@ -1,5 +1,5 @@
 error: no rules expected the token `let`
-  --> $DIR/feature-gate.rs:101:15
+  --> $DIR/feature-gate.rs:51:15
    |
 LL |     macro_rules! use_expr {
    |     --------------------- when calling this macro
@@ -8,25 +8,7 @@ LL |     use_expr!(let 0 = 1);
    |               ^^^ no rules expected this token in macro call
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:14:9
-   |
-LL |     if (let 0 = 1) {}
-   |         ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:17:11
-   |
-LL |     if (((let 0 = 1))) {}
-   |           ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:20:16
+  --> $DIR/feature-gate.rs:14:16
    |
 LL |     if true && let 0 = 1 {}
    |                ^^^^^^^^^
@@ -35,7 +17,7 @@ LL |     if true && let 0 = 1 {}
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:23:8
+  --> $DIR/feature-gate.rs:17:8
    |
 LL |     if let 0 = 1 && true {}
    |        ^^^^^^^^^
@@ -44,88 +26,7 @@ LL |     if let 0 = 1 && true {}
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:26:9
-   |
-LL |     if (let 0 = 1) && true {}
-   |         ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:29:17
-   |
-LL |     if true && (let 0 = 1) {}
-   |                 ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:32:9
-   |
-LL |     if (let 0 = 1) && (let 0 = 1) {}
-   |         ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:32:24
-   |
-LL |     if (let 0 = 1) && (let 0 = 1) {}
-   |                        ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:36:8
-   |
-LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |        ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:36:21
-   |
-LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |                     ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:36:35
-   |
-LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |                                   ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:36:48
-   |
-LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |                                                ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:36:61
-   |
-LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |                                                             ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:43:8
+  --> $DIR/feature-gate.rs:20:8
    |
 LL |     if let Range { start: _, end: _ } = (true..true) && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -134,25 +35,7 @@ LL |     if let Range { start: _, end: _ } = (true..true) && false {}
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:50:12
-   |
-LL |     while (let 0 = 1) {}
-   |            ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:53:14
-   |
-LL |     while (((let 0 = 1))) {}
-   |              ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:56:19
+  --> $DIR/feature-gate.rs:27:19
    |
 LL |     while true && let 0 = 1 {}
    |                   ^^^^^^^^^
@@ -161,7 +44,7 @@ LL |     while true && let 0 = 1 {}
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:59:11
+  --> $DIR/feature-gate.rs:30:11
    |
 LL |     while let 0 = 1 && true {}
    |           ^^^^^^^^^
@@ -170,88 +53,7 @@ LL |     while let 0 = 1 && true {}
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:62:12
-   |
-LL |     while (let 0 = 1) && true {}
-   |            ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:65:20
-   |
-LL |     while true && (let 0 = 1) {}
-   |                    ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:68:12
-   |
-LL |     while (let 0 = 1) && (let 0 = 1) {}
-   |            ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:68:27
-   |
-LL |     while (let 0 = 1) && (let 0 = 1) {}
-   |                           ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:72:11
-   |
-LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |           ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:72:24
-   |
-LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |                        ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:72:38
-   |
-LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |                                      ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:72:51
-   |
-LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |                                                   ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:72:64
-   |
-LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-   |                                                                ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:79:11
+  --> $DIR/feature-gate.rs:33:11
    |
 LL |     while let Range { start: _, end: _ } = (true..true) && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -260,7 +62,7 @@ LL |     while let Range { start: _, end: _ } = (true..true) && false {}
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:99:20
+  --> $DIR/feature-gate.rs:49:20
    |
 LL |     #[cfg(FALSE)] (let 0 = 1);
    |                    ^^^^^^^^^
@@ -269,7 +71,7 @@ LL |     #[cfg(FALSE)] (let 0 = 1);
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:86:17
+  --> $DIR/feature-gate.rs:40:17
    |
 LL |     noop_expr!((let 0 = 1));
    |                 ^^^^^^^^^
@@ -277,24 +79,6 @@ LL |     noop_expr!((let 0 = 1));
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:95:16
-   |
-LL |     use_expr!((let 0 = 1 && 0 == 0));
-   |                ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:97:16
-   |
-LL |     use_expr!((let 0 = 1));
-   |                ^^^^^^^^^
-   |
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-   = help: add `#![feature(let_chains)]` to the crate attributes to enable
-
-error: aborting due to 33 previous errors
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs b/src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs
index 96ba393bd85..e8b26154549 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs
@@ -1,4 +1,4 @@
-// compiler-flags: -Z parse-only
+// compile-flags: -Z parse-only
 
 #![feature(const_trait_impl)]
 
diff --git a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs
index cad7d76c6ab..5a17c108ccc 100644
--- a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs
+++ b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.rs
@@ -1,8 +1,25 @@
 trait Bar {}
-impl Bar for u8 {}
+
+impl Bar for i32 {}
+
+struct Qux;
+
+impl Bar for Qux {}
+
 fn foo() -> impl Bar {
-    5; //~^ ERROR the trait bound `(): Bar` is not satisfied
+    //~^ ERROR the trait bound `(): Bar` is not satisfied
+    //~| ERROR the trait bound `(): Bar` is not satisfied
+    //~| HELP the following other types implement trait `Bar`:
+    5;
+    //~^ HELP remove this semicolon
+}
+
+fn bar() -> impl Bar {
+    //~^ ERROR the trait bound `(): Bar` is not satisfied
     //~| ERROR the trait bound `(): Bar` is not satisfied
+    //~| HELP the following other types implement trait `Bar`:
+    //~| HELP the following other types implement trait `Bar`:
+    "";
 }
 
 fn main() {}
diff --git a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr
index 0de765588e5..43f8b7c66f0 100644
--- a/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr
+++ b/src/test/ui/suggestions/impl-trait-return-trailing-semicolon.stderr
@@ -1,23 +1,58 @@
 error[E0277]: the trait bound `(): Bar` is not satisfied
-  --> $DIR/impl-trait-return-trailing-semicolon.rs:3:13
+  --> $DIR/impl-trait-return-trailing-semicolon.rs:9:13
    |
 LL | fn foo() -> impl Bar {
    |             ^^^^^^^^ the trait `Bar` is not implemented for `()`
+...
 LL |     5;
-   |      - consider removing this semicolon
+   |     -- help: remove this semicolon
+   |     |
+   |     this expression has type `{integer}`, which implements `Bar`
 
 error[E0277]: the trait bound `(): Bar` is not satisfied
-  --> $DIR/impl-trait-return-trailing-semicolon.rs:3:22
+  --> $DIR/impl-trait-return-trailing-semicolon.rs:9:22
    |
 LL |   fn foo() -> impl Bar {
    |  ______________________^
+LL | |
+LL | |
+LL | |
 LL | |     5;
 LL | |
 LL | | }
    | |_^ the trait `Bar` is not implemented for `()`
    |
-   = help: the trait `Bar` is implemented for `u8`
+   = help: the following other types implement trait `Bar`:
+             Qux
+             i32
+
+error[E0277]: the trait bound `(): Bar` is not satisfied
+  --> $DIR/impl-trait-return-trailing-semicolon.rs:17:13
+   |
+LL | fn bar() -> impl Bar {
+   |             ^^^^^^^^ the trait `Bar` is not implemented for `()`
+   |
+   = help: the following other types implement trait `Bar`:
+             Qux
+             i32
+
+error[E0277]: the trait bound `(): Bar` is not satisfied
+  --> $DIR/impl-trait-return-trailing-semicolon.rs:17:22
+   |
+LL |   fn bar() -> impl Bar {
+   |  ______________________^
+LL | |
+LL | |
+LL | |
+LL | |
+LL | |     "";
+LL | | }
+   | |_^ the trait `Bar` is not implemented for `()`
+   |
+   = help: the following other types implement trait `Bar`:
+             Qux
+             i32
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/issue-81098.stderr b/src/test/ui/suggestions/issue-81098.stderr
index d62526442e9..8665f2e70a8 100644
--- a/src/test/ui/suggestions/issue-81098.stderr
+++ b/src/test/ui/suggestions/issue-81098.stderr
@@ -27,7 +27,9 @@ LL | fn ok() -> impl core::fmt::Display {
    |            ^^^^^^^^^^^^^^^^^^^^^^^ `()` cannot be formatted with the default formatter
 LL |
 LL |     1;
-   |      - consider removing this semicolon
+   |     -- help: remove this semicolon
+   |     |
+   |     this expression has type `{integer}`, which implements `std::fmt::Display`
    |
    = help: the trait `std::fmt::Display` is not implemented for `()`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
diff --git a/src/test/ui/suggestions/match-with-different-arm-types-as-stmt-instead-of-expr.stderr b/src/test/ui/suggestions/match-with-different-arm-types-as-stmt-instead-of-expr.stderr
index 7dce97468b6..60f423a1163 100644
--- a/src/test/ui/suggestions/match-with-different-arm-types-as-stmt-instead-of-expr.stderr
+++ b/src/test/ui/suggestions/match-with-different-arm-types-as-stmt-instead-of-expr.stderr
@@ -7,7 +7,7 @@ LL | fn not_all_paths(a: &str) -> u32 {
    |    implicitly returns `()` as its body has no tail or `return` expression
 ...
 LL |     };
-   |      - help: consider removing this semicolon
+   |      - help: remove this semicolon
 
 error[E0308]: `match` arms have incompatible types
   --> $DIR/match-with-different-arm-types-as-stmt-instead-of-expr.rs:26:14
diff --git a/src/test/ui/typeof/type_mismatch.stderr b/src/test/ui/typeof/type_mismatch.stderr
index e82b5e44973..e75214cd31a 100644
--- a/src/test/ui/typeof/type_mismatch.stderr
+++ b/src/test/ui/typeof/type_mismatch.stderr
@@ -3,6 +3,11 @@ error[E0516]: `typeof` is a reserved keyword but unimplemented
    |
 LL |     let b: typeof(a) = 1i8;
    |            ^^^^^^^^^ reserved keyword
+   |
+help: consider replacing `typeof(...)` with an actual type
+   |
+LL |     let b: u8 = 1i8;
+   |            ~~
 
 error[E0308]: mismatched types
   --> $DIR/type_mismatch.rs:5:24
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 891531951c1..fe411220484 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
@@ -211,7 +211,8 @@ fn check_statement<'tcx>(
 
         StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body),
         // just an assignment
-        StatementKind::SetDiscriminant { place, .. } => check_place(tcx, **place, span, body),
+        StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => 
+            check_place(tcx, **place, span, body),
 
         StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => {
             check_operand(tcx, dst, span, body)?;
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 8a72b44e2b5..858a576dcb4 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -189,6 +189,8 @@ mod directives {
     pub const STDERR_PER_BITWIDTH: &'static str = "stderr-per-bitwidth";
     pub const INCREMENTAL: &'static str = "incremental";
     pub const KNOWN_BUG: &'static str = "known-bug";
+    // This isn't a real directive, just one that is probably mistyped often
+    pub const INCORRECT_COMPILER_FLAGS: &'static str = "compiler-flags";
 }
 
 impl TestProps {
@@ -282,6 +284,9 @@ impl TestProps {
                 if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) {
                     self.compile_flags.extend(flags.split_whitespace().map(|s| s.to_owned()));
                 }
+                if config.parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS).is_some() {
+                    panic!("`compiler-flags` directive should be spelled `compile-flags`");
+                }
 
                 if let Some(edition) = config.parse_edition(ln) {
                     self.compile_flags.push(format!("--edition={}", edition));