about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast_ir/src/lib.rs8
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs96
-rw-r--r--compiler/rustc_codegen_cranelift/.cirrus.yml5
-rw-r--r--compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js4
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/main.yml3
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch13
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh12
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs11
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs72
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs46
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs114
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs7
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs67
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs7
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs8
-rw-r--r--compiler/rustc_mir_transform/src/coroutine/by_move_body.rs78
-rw-r--r--compiler/rustc_target/src/asm/aarch64.rs56
-rw-r--r--compiler/rustc_target/src/asm/mod.rs16
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs13
-rw-r--r--src/doc/unstable-book/src/language-features/asm-experimental-arch.md32
-rw-r--r--src/tools/compiletest/src/header.rs36
-rw-r--r--src/tools/compiletest/src/header/tests.rs21
-rw-r--r--src/tools/tidy/src/issues.txt1
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--tests/assembly/asm/aarch64-types.rs155
-rw-r--r--tests/ui/asm/aarch64/type-check-2-2.stderr8
-rw-r--r--tests/ui/asm/x86_64/type-check-5.stderr8
-rw-r--r--tests/ui/async-await/async-borrowck-escaping-closure-error.rs1
-rw-r--r--tests/ui/async-await/async-borrowck-escaping-closure-error.stderr11
-rw-r--r--tests/ui/async-await/async-closures/moro-example.rs43
-rw-r--r--tests/ui/async-await/async-closures/no-borrow-from-env.rs44
-rw-r--r--tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.rs47
-rw-r--r--tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr152
-rw-r--r--tests/ui/binop/issue-77910-1.stderr4
-rw-r--r--tests/ui/binop/issue-77910-2.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-block-uninit.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-break-uninit-2.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-break-uninit.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-init-in-fn-expr.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-init-in-fru.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-init-op-equal.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-init-plus-equal.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-return.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-storage-dead.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-uninit-after-item.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-uninit-in-assignop.stderr40
-rw-r--r--tests/ui/borrowck/borrowck-uninit-ref-chain.stderr10
-rw-r--r--tests/ui/borrowck/borrowck-uninit.stderr4
-rw-r--r--tests/ui/borrowck/borrowck-use-in-index-lvalue.fixed11
-rw-r--r--tests/ui/borrowck/borrowck-use-in-index-lvalue.rs2
-rw-r--r--tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr8
-rw-r--r--tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.fixed12
-rw-r--r--tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs2
-rw-r--r--tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr6
-rw-r--r--tests/ui/borrowck/borrowck-use-uninitialized-in-cast.fixed10
-rw-r--r--tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs2
-rw-r--r--tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr6
-rw-r--r--tests/ui/borrowck/issue-103250.stderr4
-rw-r--r--tests/ui/borrowck/issue-24267-flow-exit.stderr8
-rw-r--r--tests/ui/borrowck/issue-62107-match-arm-scopes.stderr4
-rw-r--r--tests/ui/borrowck/suggest-assign-rvalue.stderr22
-rw-r--r--tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr4
-rw-r--r--tests/ui/const-generics/const-generic-default-wont-borrowck.fixed6
-rw-r--r--tests/ui/const-generics/const-generic-default-wont-borrowck.rs3
-rw-r--r--tests/ui/const-generics/const-generic-default-wont-borrowck.stderr6
-rw-r--r--tests/ui/consts/issue-78655.stderr4
-rw-r--r--tests/ui/drop/repeat-drop-2.stderr4
-rw-r--r--tests/ui/issues/issue-21596.rs5
-rw-r--r--tests/ui/issues/issue-21596.stderr15
-rw-r--r--tests/ui/issues/issue-27042.stderr2
-rw-r--r--tests/ui/loops/loop-break-value.rs4
-rw-r--r--tests/ui/loops/loop-break-value.stderr77
-rw-r--r--tests/ui/loops/loop-labeled-break-value.stderr6
-rw-r--r--tests/ui/loops/loop-proper-liveness.stderr4
-rw-r--r--tests/ui/loops/loop-properly-diverging-2.stderr2
-rw-r--r--tests/ui/methods/suggest-convert-ptr-to-ref.rs17
-rw-r--r--tests/ui/methods/suggest-convert-ptr-to-ref.stderr70
-rw-r--r--tests/ui/moves/issue-72649-uninit-in-loop.stderr8
-rw-r--r--tests/ui/moves/move-into-dead-array-1.stderr4
-rw-r--r--tests/ui/moves/move-of-addr-of-mut.stderr4
-rw-r--r--tests/ui/never_type/issue-52443.stderr2
-rw-r--r--tests/ui/nll/match-cfg-fake-edges.stderr8
-rw-r--r--tests/ui/nll/match-on-borrowed.stderr4
-rw-r--r--tests/ui/type/type-error-break-tail.stderr2
-rw-r--r--tests/ui/uninhabited/privately-uninhabited-mir-call.fixed31
-rw-r--r--tests/ui/uninhabited/privately-uninhabited-mir-call.rs2
-rw-r--r--tests/ui/uninhabited/privately-uninhabited-mir-call.stderr4
95 files changed, 1245 insertions, 481 deletions
diff --git a/compiler/rustc_ast_ir/src/lib.rs b/compiler/rustc_ast_ir/src/lib.rs
index ff7a1552047..9ff2e32f06b 100644
--- a/compiler/rustc_ast_ir/src/lib.rs
+++ b/compiler/rustc_ast_ir/src/lib.rs
@@ -51,6 +51,14 @@ impl Mutability {
         }
     }
 
+    /// Returns `"const"` or `"mut"` depending on the mutability.
+    pub fn ptr_str(self) -> &'static str {
+        match self {
+            Mutability::Not => "const",
+            Mutability::Mut => "mut",
+        }
+    }
+
     /// Returns `""` (empty string) or `"mutably "` depending on the mutability.
     pub fn mutably_str(self) -> &'static str {
         match self {
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 47bd24f1e14..c593d5a30b6 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -652,6 +652,68 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         err
     }
 
+    fn ty_kind_suggestion(&self, ty: Ty<'tcx>) -> Option<String> {
+        // Keep in sync with `rustc_hir_analysis/src/check/mod.rs:ty_kind_suggestion`.
+        // FIXME: deduplicate the above.
+        let tcx = self.infcx.tcx;
+        let implements_default = |ty| {
+            let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
+                return false;
+            };
+            self.infcx
+                .type_implements_trait(default_trait, [ty], self.param_env)
+                .must_apply_modulo_regions()
+        };
+
+        Some(match ty.kind() {
+            ty::Never | ty::Error(_) => return None,
+            ty::Bool => "false".to_string(),
+            ty::Char => "\'x\'".to_string(),
+            ty::Int(_) | ty::Uint(_) => "42".into(),
+            ty::Float(_) => "3.14159".into(),
+            ty::Slice(_) => "[]".to_string(),
+            ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => {
+                "vec![]".to_string()
+            }
+            ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::String) => {
+                "String::new()".to_string()
+            }
+            ty::Adt(def, args) if def.is_box() => {
+                format!("Box::new({})", self.ty_kind_suggestion(args[0].expect_ty())?)
+            }
+            ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Option) => {
+                "None".to_string()
+            }
+            ty::Adt(def, args) if Some(def.did()) == tcx.get_diagnostic_item(sym::Result) => {
+                format!("Ok({})", self.ty_kind_suggestion(args[0].expect_ty())?)
+            }
+            ty::Adt(_, _) if implements_default(ty) => "Default::default()".to_string(),
+            ty::Ref(_, ty, mutability) => {
+                if let (ty::Str, hir::Mutability::Not) = (ty.kind(), mutability) {
+                    "\"\"".to_string()
+                } else {
+                    let Some(ty) = self.ty_kind_suggestion(*ty) else {
+                        return None;
+                    };
+                    format!("&{}{ty}", mutability.prefix_str())
+                }
+            }
+            ty::Array(ty, len) => format!(
+                "[{}; {}]",
+                self.ty_kind_suggestion(*ty)?,
+                len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()),
+            ),
+            ty::Tuple(tys) => format!(
+                "({})",
+                tys.iter()
+                    .map(|ty| self.ty_kind_suggestion(ty))
+                    .collect::<Option<Vec<String>>>()?
+                    .join(", ")
+            ),
+            _ => "value".to_string(),
+        })
+    }
+
     fn suggest_assign_value(
         &self,
         err: &mut Diag<'_>,
@@ -661,34 +723,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
         debug!("ty: {:?}, kind: {:?}", ty, ty.kind());
 
-        let tcx = self.infcx.tcx;
-        let implements_default = |ty, param_env| {
-            let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
-                return false;
-            };
-            self.infcx
-                .type_implements_trait(default_trait, [ty], param_env)
-                .must_apply_modulo_regions()
-        };
-
-        let assign_value = match ty.kind() {
-            ty::Bool => "false",
-            ty::Float(_) => "0.0",
-            ty::Int(_) | ty::Uint(_) => "0",
-            ty::Never | ty::Error(_) => "",
-            ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => "vec![]",
-            ty::Adt(_, _) if implements_default(ty, self.param_env) => "Default::default()",
-            _ => "todo!()",
+        let Some(assign_value) = self.ty_kind_suggestion(ty) else {
+            return;
         };
 
-        if !assign_value.is_empty() {
-            err.span_suggestion_verbose(
-                sugg_span.shrink_to_hi(),
-                "consider assigning a value",
-                format!(" = {assign_value}"),
-                Applicability::MaybeIncorrect,
-            );
-        }
+        err.span_suggestion_verbose(
+            sugg_span.shrink_to_hi(),
+            "consider assigning a value",
+            format!(" = {assign_value}"),
+            Applicability::MaybeIncorrect,
+        );
     }
 
     fn suggest_borrow_fn_like(
diff --git a/compiler/rustc_codegen_cranelift/.cirrus.yml b/compiler/rustc_codegen_cranelift/.cirrus.yml
index 97c2f45d31e..5a464bfac36 100644
--- a/compiler/rustc_codegen_cranelift/.cirrus.yml
+++ b/compiler/rustc_codegen_cranelift/.cirrus.yml
@@ -7,7 +7,7 @@ task:
     - curl https://sh.rustup.rs -sSf --output rustup.sh
     - sh rustup.sh --default-toolchain none -y --profile=minimal
   target_cache:
-    folder: target
+    folder: build/cg_clif
   prepare_script:
     - . $HOME/.cargo/env
     - ./y.sh prepare
@@ -16,4 +16,5 @@ task:
     # Disabling incr comp reduces cache size and incr comp doesn't save as much
     # on CI anyway.
     - export CARGO_BUILD_INCREMENTAL=false
-    - ./y.sh test
+    # Skip rand as it fails on FreeBSD due to rust-random/rand#1355
+    - ./y.sh test --skip-test test.rust-random/rand
diff --git a/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js b/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js
index 6fcfca34ea7..1eb2b7f23b2 100644
--- a/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js
+++ b/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js
@@ -56,7 +56,7 @@ async function runOnce() {
           force: true,
         });
       } catch (e) {
-        console.log("ERROR: ", JSON.stringify(e.data, null, 2));
+        console.log("ERROR: ", JSON.stringify(e.response, null, 2));
         core.info(`creating dev tag`);
         try {
           await octokit.rest.git.createRef({
@@ -68,7 +68,7 @@ async function runOnce() {
         } catch (e) {
           // we might race with others, so assume someone else has created the
           // tag by this point.
-          console.log("failed to create tag: ", JSON.stringify(e.data, null, 2));
+          console.log("failed to create tag: ", JSON.stringify(e.response, null, 2));
         }
       }
 
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
index 913a5c5a850..14aa850ff5c 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -268,6 +268,9 @@ jobs:
     if: ${{ github.ref == 'refs/heads/master' }}
     needs: [rustfmt, test, bench, dist]
 
+    permissions:
+      contents: write # for creating the dev tag and release
+
     concurrency:
       group: release-dev
       cancel-in-progress: true
diff --git a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch
index 646928893e9..a3f370af916 100644
--- a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch
@@ -82,6 +82,19 @@ index d9de37e..8293fce 100644
  #[cfg(target_has_atomic_load_store = "ptr")]
  macro_rules! atomic_int_ptr_sized {
      ( $($target_pointer_width:literal $align:literal)* ) => { $(
+diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
+index 58b9ba4..91bbd0a 100644
+--- a/library/core/src/cell.rs
++++ b/library/core/src/cell.rs
+@@ -2246,8 +2246,6 @@ unsafe_cell_primitive_into_inner! {
+     u32 "32"
+     i64 "64"
+     u64 "64"
+-    i128 "128"
+-    u128 "128"
+     isize "ptr"
+     usize "ptr"
+ }
 --
 2.26.2.7.g19db9cfb68
 
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 09e436b3eed..3e7da4e161f 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2024-04-05"
+channel = "nightly-2024-04-11"
 components = ["rust-src", "rustc-dev", "llvm-tools"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index f42a008dc0c..8580f4557e8 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -10,14 +10,13 @@ pushd rust
 
 command -v rg >/dev/null 2>&1 || cargo install ripgrep
 
-# FIXME remove this workaround once ICE tests no longer emit an outdated nightly message
-for test in $(rg -i --files-with-matches "//@(\[.*\])? failure-status: 101" tests/ui); do
-  echo "rm $test"
+rm -r tests/ui/{unsized-locals/,lto/,linkage*} || true
+for test in $(rg --files-with-matches "lto" tests/{codegen-units,ui,incremental}); do
   rm $test
 done
 
-rm -r tests/ui/{unsized-locals/,lto/,linkage*} || true
-for test in $(rg --files-with-matches "lto" tests/{codegen-units,ui,incremental}); do
+# should-fail tests don't work when compiletest is compiled with panic=abort
+for test in $(rg --files-with-matches "//@ should-fail" tests/{codegen-units,ui,incremental}); do
   rm $test
 done
 
@@ -79,7 +78,6 @@ rm -r tests/run-make/fmt-write-bloat/ # tests an optimization
 # ======================
 rm tests/incremental/thinlto/cgu_invalidated_when_import_{added,removed}.rs # requires LLVM
 rm -r tests/run-make/cross-lang-lto # same
-rm -r tests/run-make/issue-7349 # same
 rm -r tests/run-make/sepcomp-inlining # same
 rm -r tests/run-make/sepcomp-separate # same
 rm -r tests/run-make/sepcomp-cci-copies # same
@@ -116,8 +114,6 @@ rm -r tests/run-make/compiler-builtins # Expects lib/rustlib/src/rust to contain
 
 # genuine bugs
 # ============
-rm tests/incremental/spike-neg1.rs # errors out for some reason
-rm tests/incremental/spike-neg2.rs # same
 rm -r tests/run-make/extern-fn-explicit-align # argument alignment not yet supported
 rm -r tests/run-make/panic-abort-eh_frame # .eh_frame emitted with panic=abort
 
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 771e5b21958..f07421431da 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -267,10 +267,19 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
         .generic_activity("codegen prelude")
         .run(|| crate::abi::codegen_fn_prelude(fx, start_block));
 
-    for (bb, bb_data) in traversal::mono_reachable(fx.mir, fx.tcx, fx.instance) {
+    let reachable_blocks = traversal::mono_reachable_as_bitset(fx.mir, fx.tcx, fx.instance);
+
+    for (bb, bb_data) in fx.mir.basic_blocks.iter_enumerated() {
         let block = fx.get_block(bb);
         fx.bcx.switch_to_block(block);
 
+        if !reachable_blocks.contains(bb) {
+            // We want to skip this block, because it's not reachable. But we still create
+            // the block so terminators in other blocks can reference it.
+            fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
+            continue;
+        }
+
         if bb_data.is_cleanup {
             // Unwinding after panicking is not supported
             continue;
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
index 96ab7a29205..eebd181341d 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
@@ -38,6 +38,14 @@ impl UnwindContext {
     }
 
     pub(crate) fn add_function(&mut self, func_id: FuncId, context: &Context, isa: &dyn TargetIsa) {
+        if let target_lexicon::OperatingSystem::MacOSX { .. } = isa.triple().operating_system {
+            // The object crate doesn't currently support DW_GNU_EH_PE_absptr, which macOS
+            // requires for unwinding tables. In addition on arm64 it currently doesn't
+            // support 32bit relocations as we currently use for the unwinding table.
+            // See gimli-rs/object#415 and rust-lang/rustc_codegen_cranelift#1371
+            return;
+        }
+
         let unwind_info = if let Some(unwind_info) =
             context.compiled_code().unwrap().create_unwind_info(isa).unwrap()
         {
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 500904ce188..e09869cf425 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -220,7 +220,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
         constraints.append(&mut clobbers);
         if !options.contains(InlineAsmOptions::PRESERVES_FLAGS) {
             match asm_arch {
-                InlineAsmArch::AArch64 | InlineAsmArch::Arm => {
+                InlineAsmArch::AArch64 | InlineAsmArch::Arm64EC | InlineAsmArch::Arm => {
                     constraints.push("~{cc}".to_string());
                 }
                 InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 8d4ae10d4bf..961b643fa25 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -22,7 +22,6 @@ use rustc_middle::ty::{
     AdtDef, ParamEnv, RegionKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
 };
 use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
-use rustc_span::symbol::sym;
 use rustc_target::abi::FieldIdx;
 use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 8760901b71b..938c0a19e33 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -81,6 +81,7 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_errors::{pluralize, struct_span_code_err, Diag};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
+use rustc_hir::Mutability;
 use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::error_reporting::ObligationCauseExt as _;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
@@ -91,10 +92,11 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{GenericArgs, GenericArgsRef};
 use rustc_session::parse::feature_err;
-use rustc_span::symbol::{kw, Ident};
-use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP};
+use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::{def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::ObligationCtxt;
@@ -466,14 +468,64 @@ fn fn_sig_suggestion<'tcx>(
     )
 }
 
-pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
+pub fn ty_kind_suggestion<'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<String> {
+    // Keep in sync with `rustc_borrowck/src/diagnostics/conflict_errors.rs:ty_kind_suggestion`.
+    // FIXME: deduplicate the above.
+    let implements_default = |ty| {
+        let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
+            return false;
+        };
+        let infcx = tcx.infer_ctxt().build();
+        infcx
+            .type_implements_trait(default_trait, [ty], ty::ParamEnv::reveal_all())
+            .must_apply_modulo_regions()
+    };
     Some(match ty.kind() {
-        ty::Bool => "true",
-        ty::Char => "'a'",
-        ty::Int(_) | ty::Uint(_) => "42",
-        ty::Float(_) => "3.14159",
-        ty::Error(_) | ty::Never => return None,
-        _ => "value",
+        ty::Never | ty::Error(_) => return None,
+        ty::Bool => "false".to_string(),
+        ty::Char => "\'x\'".to_string(),
+        ty::Int(_) | ty::Uint(_) => "42".into(),
+        ty::Float(_) => "3.14159".into(),
+        ty::Slice(_) => "[]".to_string(),
+        ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => {
+            "vec![]".to_string()
+        }
+        ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::String) => {
+            "String::new()".to_string()
+        }
+        ty::Adt(def, args) if def.is_box() => {
+            format!("Box::new({})", ty_kind_suggestion(args[0].expect_ty(), tcx)?)
+        }
+        ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Option) => {
+            "None".to_string()
+        }
+        ty::Adt(def, args) if Some(def.did()) == tcx.get_diagnostic_item(sym::Result) => {
+            format!("Ok({})", ty_kind_suggestion(args[0].expect_ty(), tcx)?)
+        }
+        ty::Adt(_, _) if implements_default(ty) => "Default::default()".to_string(),
+        ty::Ref(_, ty, mutability) => {
+            if let (ty::Str, Mutability::Not) = (ty.kind(), mutability) {
+                "\"\"".to_string()
+            } else {
+                let Some(ty) = ty_kind_suggestion(*ty, tcx) else {
+                    return None;
+                };
+                format!("&{}{ty}", mutability.prefix_str())
+            }
+        }
+        ty::Array(ty, len) => format!(
+            "[{}; {}]",
+            ty_kind_suggestion(*ty, tcx)?,
+            len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()),
+        ),
+        ty::Tuple(tys) => format!(
+            "({})",
+            tys.iter()
+                .map(|ty| ty_kind_suggestion(ty, tcx))
+                .collect::<Option<Vec<String>>>()?
+                .join(", ")
+        ),
+        _ => "value".to_string(),
     })
 }
 
@@ -511,7 +563,7 @@ fn suggestion_signature<'tcx>(
         }
         ty::AssocKind::Const => {
             let ty = tcx.type_of(assoc.def_id).instantiate_identity();
-            let val = ty_kind_suggestion(ty).unwrap_or("todo!()");
+            let val = ty_kind_suggestion(ty, tcx).unwrap_or_else(|| "value".to_string());
             format!("const {}: {} = {};", assoc.name, ty, val)
         }
     }
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index affd678fc6c..3d16f1420d9 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -718,6 +718,11 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self))]
+    fn visit_pattern_type_pattern(&mut self, p: &'tcx hir::Pat<'tcx>) {
+        intravisit::walk_pat(self, p)
+    }
+
+    #[instrument(level = "debug", skip(self))]
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         use self::hir::TraitItemKind::*;
         match trait_item.kind {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 9fb8b4ac40e..63aeb165a48 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2234,11 +2234,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                                         .type_of(def_id)
                                         .no_bound_vars()
                                         .expect("const parameter types cannot be generic");
-                                    let item_def_id = tcx.parent(def_id);
-                                    let generics = tcx.generics_of(item_def_id);
-                                    let index = generics.param_def_id_to_index[&def_id];
-                                    let name = tcx.item_name(def_id);
-                                    ty::Const::new_param(tcx, ty::ParamConst::new(index, name), ty)
+                                    self.lower_const_param(expr.hir_id, ty)
                                 }
 
                                 _ => {
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 7a1a2c498aa..8f30c3fd377 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -694,10 +694,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             );
                             let error = Some(Sorts(ExpectedFound { expected: ty, found: e_ty }));
                             self.annotate_loop_expected_due_to_inference(err, expr, error);
-                            if let Some(val) = ty_kind_suggestion(ty) {
+                            if let Some(val) = ty_kind_suggestion(ty, tcx) {
                                 err.span_suggestion_verbose(
                                     expr.span.shrink_to_hi(),
-                                    "give it a value of the expected type",
+                                    "give the `break` a value of the expected type",
                                     format!(" {val}"),
                                     Applicability::HasPlaceholders,
                                 );
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index a199f57aad9..754866c85c4 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -529,16 +529,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Applicability::MachineApplicable,
             );
         }
-        if let ty::RawPtr(_, _) = &rcvr_ty.kind() {
-            err.note(
-                "try using `<*const T>::as_ref()` to get a reference to the \
-                 type behind the pointer: https://doc.rust-lang.org/std/\
-                 primitive.pointer.html#method.as_ref",
-            );
-            err.note(
-                "using `<*const T>::as_ref()` on a pointer which is unaligned or points \
-                 to invalid or uninitialized memory is undefined behavior",
+
+        // on pointers, check if the method would exist on a reference
+        if let SelfSource::MethodCall(rcvr_expr) = source
+            && let ty::RawPtr(ty, ptr_mutbl) = *rcvr_ty.kind()
+            && let Ok(pick) = self.lookup_probe_for_diagnostic(
+                item_name,
+                Ty::new_ref(tcx, ty::Region::new_error_misc(tcx), ty, ptr_mutbl),
+                self.tcx.hir().expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id)),
+                ProbeScope::TraitsInScope,
+                None,
+            )
+            && let ty::Ref(_, _, sugg_mutbl) = *pick.self_ty.kind()
+            && (sugg_mutbl.is_not() || ptr_mutbl.is_mut())
+        {
+            let (method, method_anchor) = match sugg_mutbl {
+                Mutability::Not => {
+                    let method_anchor = match ptr_mutbl {
+                        Mutability::Not => "as_ref",
+                        Mutability::Mut => "as_ref-1",
+                    };
+                    ("as_ref", method_anchor)
+                }
+                Mutability::Mut => ("as_mut", "as_mut"),
+            };
+            err.span_note(
+                tcx.def_span(pick.item.def_id),
+                format!("the method `{item_name}` exists on the type `{ty}`", ty = pick.self_ty),
             );
+            let mut_str = ptr_mutbl.ptr_str();
+            err.note(format!(
+                "you might want to use the unsafe method `<*{mut_str} T>::{method}` to get \
+                an optional reference to the value behind the pointer"
+            ));
+            err.note(format!(
+                "read the documentation for `<*{mut_str} T>::{method}` and ensure you satisfy its \
+                safety preconditions before calling it to avoid undefined behavior: \
+                https://doc.rust-lang.org/std/primitive.pointer.html#method.{method_anchor}"
+            ));
         }
 
         let mut ty_span = match rcvr_ty.kind() {
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index c987bfb9a0e..ef569b4bef3 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -367,37 +367,48 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ty::INNERMOST,
                 ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::BrEnv },
             );
+
+            let num_args = args
+                .as_coroutine_closure()
+                .coroutine_closure_sig()
+                .skip_binder()
+                .tupled_inputs_ty
+                .tuple_fields()
+                .len();
+            let typeck_results = self.typeck_results.borrow();
+
             let tupled_upvars_ty_for_borrow = Ty::new_tup_from_iter(
                 self.tcx,
-                self.typeck_results
-                    .borrow()
-                    .closure_min_captures_flattened(
-                        self.tcx.coroutine_for_closure(closure_def_id).expect_local(),
-                    )
-                    // Skip the captures that are just moving the closure's args
-                    // into the coroutine. These are always by move, and we append
-                    // those later in the `CoroutineClosureSignature` helper functions.
-                    .skip(
-                        args.as_coroutine_closure()
-                            .coroutine_closure_sig()
-                            .skip_binder()
-                            .tupled_inputs_ty
-                            .tuple_fields()
-                            .len(),
-                    )
-                    .map(|captured_place| {
-                        let upvar_ty = captured_place.place.ty();
-                        let capture = captured_place.info.capture_kind;
+                ty::analyze_coroutine_closure_captures(
+                    typeck_results.closure_min_captures_flattened(closure_def_id),
+                    typeck_results
+                        .closure_min_captures_flattened(
+                            self.tcx.coroutine_for_closure(closure_def_id).expect_local(),
+                        )
+                        // Skip the captures that are just moving the closure's args
+                        // into the coroutine. These are always by move, and we append
+                        // those later in the `CoroutineClosureSignature` helper functions.
+                        .skip(num_args),
+                    |(_, parent_capture), (_, child_capture)| {
+                        // This is subtle. See documentation on function.
+                        let needs_ref = should_reborrow_from_env_of_parent_coroutine_closure(
+                            parent_capture,
+                            child_capture,
+                        );
+
+                        let upvar_ty = child_capture.place.ty();
+                        let capture = child_capture.info.capture_kind;
                         // Not all upvars are captured by ref, so use
                         // `apply_capture_kind_on_capture_ty` to ensure that we
                         // compute the right captured type.
-                        apply_capture_kind_on_capture_ty(
+                        return apply_capture_kind_on_capture_ty(
                             self.tcx,
                             upvar_ty,
                             capture,
-                            Some(closure_env_region),
-                        )
-                    }),
+                            if needs_ref { Some(closure_env_region) } else { child_capture.region },
+                        );
+                    },
+                ),
             );
             let coroutine_captures_by_ref_ty = Ty::new_fn_ptr(
                 self.tcx,
@@ -1761,6 +1772,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 }
 
+/// Determines whether a child capture that is derived from a parent capture
+/// should be borrowed with the lifetime of the parent coroutine-closure's env.
+///
+/// There are two cases when this needs to happen:
+///
+/// (1.) Are we borrowing data owned by the parent closure? We can determine if
+/// that is the case by checking if the parent capture is by move, EXCEPT if we
+/// apply a deref projection, which means we're reborrowing a reference that we
+/// captured by move.
+///
+/// ```rust
+/// #![feature(async_closure)]
+/// let x = &1i32; // Let's call this lifetime `'1`.
+/// let c = async move || {
+///     println!("{:?}", *x);
+///     // Even though the inner coroutine borrows by ref, we're only capturing `*x`,
+///     // not `x`, so the inner closure is allowed to reborrow the data for `'1`.
+/// };
+/// ```
+///
+/// (2.) If a coroutine is mutably borrowing from a parent capture, then that
+/// mutable borrow cannot live for longer than either the parent *or* the borrow
+/// that we have on the original upvar. Therefore we always need to borrow the
+/// child capture with the lifetime of the parent coroutine-closure's env.
+///
+/// ```rust
+/// #![feature(async_closure)]
+/// let mut x = 1i32;
+/// let c = async || {
+///     x = 1;
+///     // The parent borrows `x` for some `&'1 mut i32`.
+///     // However, when we call `c()`, we implicitly autoref for the signature of
+///     // `AsyncFnMut::async_call_mut`. Let's call that lifetime `'call`. Since
+///     // the maximum that `&'call mut &'1 mut i32` can be reborrowed is `&'call mut i32`,
+///     // the inner coroutine should capture w/ the lifetime of the coroutine-closure.
+/// };
+/// ```
+///
+/// If either of these cases apply, then we should capture the borrow with the
+/// lifetime of the parent coroutine-closure's env. Luckily, if this function is
+/// not correct, then the program is not unsound, since we still borrowck and validate
+/// the choices made from this function -- the only side-effect is that the user
+/// may receive unnecessary borrowck errors.
+fn should_reborrow_from_env_of_parent_coroutine_closure<'tcx>(
+    parent_capture: &ty::CapturedPlace<'tcx>,
+    child_capture: &ty::CapturedPlace<'tcx>,
+) -> bool {
+    // (1.)
+    (!parent_capture.is_by_ref()
+        && !matches!(
+            child_capture.place.projections.get(parent_capture.place.projections.len()),
+            Some(Projection { kind: ProjectionKind::Deref, .. })
+        ))
+        // (2.)
+        || matches!(child_capture.info.capture_kind, UpvarCapture::ByRef(ty::BorrowKind::MutBorrow))
+}
+
 /// Truncate the capture so that the place being borrowed is in accordance with RFC 1240,
 /// which states that it's unsafe to take a reference into a struct marked `repr(packed)`.
 fn restrict_repr_packed_field_ref_capture<'tcx>(
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 41df2e3b587..15bd5c08965 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -978,12 +978,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
             CopyForDeref(ref place) => write!(fmt, "deref_copy {place:#?}"),
 
             AddressOf(mutability, ref place) => {
-                let kind_str = match mutability {
-                    Mutability::Mut => "mut",
-                    Mutability::Not => "const",
-                };
-
-                write!(fmt, "&raw {kind_str} {place:?}")
+                write!(fmt, "&raw {mut_str} {place:?}", mut_str = mutability.ptr_str())
             }
 
             Aggregate(ref kind, ref places) => {
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 95d1e08b58b..211d403998f 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -6,6 +6,7 @@ use crate::{mir, ty};
 use std::fmt::Write;
 
 use crate::query::Providers;
+use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
@@ -415,6 +416,72 @@ impl BorrowKind {
     }
 }
 
+pub fn analyze_coroutine_closure_captures<'a, 'tcx: 'a, T>(
+    parent_captures: impl IntoIterator<Item = &'a CapturedPlace<'tcx>>,
+    child_captures: impl IntoIterator<Item = &'a CapturedPlace<'tcx>>,
+    mut for_each: impl FnMut((usize, &'a CapturedPlace<'tcx>), (usize, &'a CapturedPlace<'tcx>)) -> T,
+) -> impl Iterator<Item = T> + Captures<'a> + Captures<'tcx> {
+    std::iter::from_coroutine(move || {
+        let mut child_captures = child_captures.into_iter().enumerate().peekable();
+
+        // One parent capture may correspond to several child captures if we end up
+        // refining the set of captures via edition-2021 precise captures. We want to
+        // match up any number of child captures with one parent capture, so we keep
+        // peeking off this `Peekable` until the child doesn't match anymore.
+        for (parent_field_idx, parent_capture) in parent_captures.into_iter().enumerate() {
+            // Make sure we use every field at least once, b/c why are we capturing something
+            // if it's not used in the inner coroutine.
+            let mut field_used_at_least_once = false;
+
+            // A parent matches a child if they share the same prefix of projections.
+            // The child may have more, if it is capturing sub-fields out of
+            // something that is captured by-move in the parent closure.
+            while child_captures.peek().map_or(false, |(_, child_capture)| {
+                child_prefix_matches_parent_projections(parent_capture, child_capture)
+            }) {
+                let (child_field_idx, child_capture) = child_captures.next().unwrap();
+                // This analysis only makes sense if the parent capture is a
+                // prefix of the child capture.
+                assert!(
+                    child_capture.place.projections.len() >= parent_capture.place.projections.len(),
+                    "parent capture ({parent_capture:#?}) expected to be prefix of \
+                    child capture ({child_capture:#?})"
+                );
+
+                yield for_each(
+                    (parent_field_idx, parent_capture),
+                    (child_field_idx, child_capture),
+                );
+
+                field_used_at_least_once = true;
+            }
+
+            // Make sure the field was used at least once.
+            assert!(
+                field_used_at_least_once,
+                "we captured {parent_capture:#?} but it was not used in the child coroutine?"
+            );
+        }
+        assert_eq!(child_captures.next(), None, "leftover child captures?");
+    })
+}
+
+fn child_prefix_matches_parent_projections(
+    parent_capture: &ty::CapturedPlace<'_>,
+    child_capture: &ty::CapturedPlace<'_>,
+) -> bool {
+    let HirPlaceBase::Upvar(parent_base) = parent_capture.place.base else {
+        bug!("expected capture to be an upvar");
+    };
+    let HirPlaceBase::Upvar(child_base) = child_capture.place.base else {
+        bug!("expected capture to be an upvar");
+    };
+
+    parent_base.var_path.hir_id == child_base.var_path.hir_id
+        && std::iter::zip(&child_capture.place.projections, &parent_capture.place.projections)
+            .all(|(child, parent)| child.kind == parent.kind)
+}
+
 pub fn provide(providers: &mut Providers) {
     *providers = Providers { closure_typeinfo, ..*providers }
 }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index ee4dc9744ac..e6b773ae512 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -77,9 +77,10 @@ pub use rustc_type_ir::ConstKind::{
 pub use rustc_type_ir::*;
 
 pub use self::closure::{
-    is_ancestor_or_same_capture, place_to_string_for_capture, BorrowKind, CaptureInfo,
-    CapturedPlace, ClosureTypeInfo, MinCaptureInformationMap, MinCaptureList,
-    RootVariableMinCaptureList, UpvarCapture, UpvarId, UpvarPath, CAPTURE_STRUCT_LOCAL,
+    analyze_coroutine_closure_captures, is_ancestor_or_same_capture, place_to_string_for_capture,
+    BorrowKind, CaptureInfo, CapturedPlace, ClosureTypeInfo, MinCaptureInformationMap,
+    MinCaptureList, RootVariableMinCaptureList, UpvarCapture, UpvarId, UpvarPath,
+    CAPTURE_STRUCT_LOCAL,
 };
 pub use self::consts::{
     Const, ConstData, ConstInt, ConstKind, Expr, ScalarInt, UnevaluatedConst, ValTree,
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 20ebd87c3d4..0bd009cd51d 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -671,13 +671,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 p!("(", print(ty), ") is ", write("{pat:?}"))
             }
             ty::RawPtr(ty, mutbl) => {
-                p!(write(
-                    "*{} ",
-                    match mutbl {
-                        hir::Mutability::Mut => "mut",
-                        hir::Mutability::Not => "const",
-                    }
-                ));
+                p!(write("*{} ", mutbl.ptr_str()));
                 p!(print(ty))
             }
             ty::Ref(r, ty, mutbl) => {
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index b26f968bf5e..3d6c1a95204 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -71,7 +71,7 @@
 
 use rustc_data_structures::unord::UnordMap;
 use rustc_hir as hir;
-use rustc_middle::hir::place::{PlaceBase, Projection, ProjectionKind};
+use rustc_middle::hir::place::{Projection, ProjectionKind};
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::{self, dump_mir, MirPass};
 use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt, TypeVisitableExt};
@@ -124,44 +124,10 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
             .tuple_fields()
             .len();
 
-        let mut field_remapping = UnordMap::default();
-
-        let mut child_captures = tcx
-            .closure_captures(coroutine_def_id)
-            .iter()
-            .copied()
-            // By construction we capture all the args first.
-            .skip(num_args)
-            .enumerate()
-            .peekable();
-
-        // One parent capture may correspond to several child captures if we end up
-        // refining the set of captures via edition-2021 precise captures. We want to
-        // match up any number of child captures with one parent capture, so we keep
-        // peeking off this `Peekable` until the child doesn't match anymore.
-        for (parent_field_idx, parent_capture) in
-            tcx.closure_captures(parent_def_id).iter().copied().enumerate()
-        {
-            // Make sure we use every field at least once, b/c why are we capturing something
-            // if it's not used in the inner coroutine.
-            let mut field_used_at_least_once = false;
-
-            // A parent matches a child if they share the same prefix of projections.
-            // The child may have more, if it is capturing sub-fields out of
-            // something that is captured by-move in the parent closure.
-            while child_captures.peek().map_or(false, |(_, child_capture)| {
-                child_prefix_matches_parent_projections(parent_capture, child_capture)
-            }) {
-                let (child_field_idx, child_capture) = child_captures.next().unwrap();
-
-                // This analysis only makes sense if the parent capture is a
-                // prefix of the child capture.
-                assert!(
-                    child_capture.place.projections.len() >= parent_capture.place.projections.len(),
-                    "parent capture ({parent_capture:#?}) expected to be prefix of \
-                    child capture ({child_capture:#?})"
-                );
-
+        let field_remapping: UnordMap<_, _> = ty::analyze_coroutine_closure_captures(
+            tcx.closure_captures(parent_def_id).iter().copied(),
+            tcx.closure_captures(coroutine_def_id).iter().skip(num_args).copied(),
+            |(parent_field_idx, parent_capture), (child_field_idx, child_capture)| {
                 // Store this set of additional projections (fields and derefs).
                 // We need to re-apply them later.
                 let child_precise_captures =
@@ -192,7 +158,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
                     ),
                 };
 
-                field_remapping.insert(
+                (
                     FieldIdx::from_usize(child_field_idx + num_args),
                     (
                         FieldIdx::from_usize(parent_field_idx + num_args),
@@ -200,18 +166,10 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
                         needs_deref,
                         child_precise_captures,
                     ),
-                );
-
-                field_used_at_least_once = true;
-            }
-
-            // Make sure the field was used at least once.
-            assert!(
-                field_used_at_least_once,
-                "we captured {parent_capture:#?} but it was not used in the child coroutine?"
-            );
-        }
-        assert_eq!(child_captures.next(), None, "leftover child captures?");
+                )
+            },
+        )
+        .collect();
 
         if coroutine_kind == ty::ClosureKind::FnOnce {
             assert_eq!(field_remapping.len(), tcx.closure_captures(parent_def_id).len());
@@ -241,22 +199,6 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
     }
 }
 
-fn child_prefix_matches_parent_projections(
-    parent_capture: &ty::CapturedPlace<'_>,
-    child_capture: &ty::CapturedPlace<'_>,
-) -> bool {
-    let PlaceBase::Upvar(parent_base) = parent_capture.place.base else {
-        bug!("expected capture to be an upvar");
-    };
-    let PlaceBase::Upvar(child_base) = child_capture.place.base else {
-        bug!("expected capture to be an upvar");
-    };
-
-    parent_base.var_path.hir_id == child_base.var_path.hir_id
-        && std::iter::zip(&child_capture.place.projections, &parent_capture.place.projections)
-            .all(|(child, parent)| child.kind == parent.kind)
-}
-
 struct MakeByMoveBody<'tcx> {
     tcx: TyCtxt<'tcx>,
     field_remapping: UnordMap<FieldIdx, (FieldIdx, Ty<'tcx>, bool, &'tcx [Projection<'tcx>])>,
diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs
index 70528c1222c..5ae9a2e2058 100644
--- a/compiler/rustc_target/src/asm/aarch64.rs
+++ b/compiler/rustc_target/src/asm/aarch64.rs
@@ -87,6 +87,20 @@ fn reserved_x18(
     }
 }
 
+fn restricted_for_arm64ec(
+    arch: InlineAsmArch,
+    _reloc_model: RelocModel,
+    _target_features: &FxIndexSet<Symbol>,
+    _target: &Target,
+    _is_clobber: bool,
+) -> Result<(), &'static str> {
+    if arch == InlineAsmArch::Arm64EC {
+        Err("x13, x14, x23, x24, x28, v16-v31 cannot be used for Arm64EC")
+    } else {
+        Ok(())
+    }
+}
+
 def_regs! {
     AArch64 AArch64InlineAsmReg AArch64InlineAsmRegClass {
         x0: reg = ["x0", "w0"],
@@ -102,8 +116,8 @@ def_regs! {
         x10: reg = ["x10", "w10"],
         x11: reg = ["x11", "w11"],
         x12: reg = ["x12", "w12"],
-        x13: reg = ["x13", "w13"],
-        x14: reg = ["x14", "w14"],
+        x13: reg = ["x13", "w13"] % restricted_for_arm64ec,
+        x14: reg = ["x14", "w14"] % restricted_for_arm64ec,
         x15: reg = ["x15", "w15"],
         x16: reg = ["x16", "w16"],
         x17: reg = ["x17", "w17"],
@@ -111,12 +125,12 @@ def_regs! {
         x20: reg = ["x20", "w20"],
         x21: reg = ["x21", "w21"],
         x22: reg = ["x22", "w22"],
-        x23: reg = ["x23", "w23"],
-        x24: reg = ["x24", "w24"],
+        x23: reg = ["x23", "w23"] % restricted_for_arm64ec,
+        x24: reg = ["x24", "w24"] % restricted_for_arm64ec,
         x25: reg = ["x25", "w25"],
         x26: reg = ["x26", "w26"],
         x27: reg = ["x27", "w27"],
-        x28: reg = ["x28", "w28"],
+        x28: reg = ["x28", "w28"] % restricted_for_arm64ec,
         x30: reg = ["x30", "w30", "lr", "wlr"],
         v0: vreg, vreg_low16 = ["v0", "b0", "h0", "s0", "d0", "q0", "z0"],
         v1: vreg, vreg_low16 = ["v1", "b1", "h1", "s1", "d1", "q1", "z1"],
@@ -134,22 +148,22 @@ def_regs! {
         v13: vreg, vreg_low16 = ["v13", "b13", "h13", "s13", "d13", "q13", "z13"],
         v14: vreg, vreg_low16 = ["v14", "b14", "h14", "s14", "d14", "q14", "z14"],
         v15: vreg, vreg_low16 = ["v15", "b15", "h15", "s15", "d15", "q15", "z15"],
-        v16: vreg = ["v16", "b16", "h16", "s16", "d16", "q16", "z16"],
-        v17: vreg = ["v17", "b17", "h17", "s17", "d17", "q17", "z17"],
-        v18: vreg = ["v18", "b18", "h18", "s18", "d18", "q18", "z18"],
-        v19: vreg = ["v19", "b19", "h19", "s19", "d19", "q19", "z19"],
-        v20: vreg = ["v20", "b20", "h20", "s20", "d20", "q20", "z20"],
-        v21: vreg = ["v21", "b21", "h21", "s21", "d21", "q21", "z21"],
-        v22: vreg = ["v22", "b22", "h22", "s22", "d22", "q22", "z22"],
-        v23: vreg = ["v23", "b23", "h23", "s23", "d23", "q23", "z23"],
-        v24: vreg = ["v24", "b24", "h24", "s24", "d24", "q24", "z24"],
-        v25: vreg = ["v25", "b25", "h25", "s25", "d25", "q25", "z25"],
-        v26: vreg = ["v26", "b26", "h26", "s26", "d26", "q26", "z26"],
-        v27: vreg = ["v27", "b27", "h27", "s27", "d27", "q27", "z27"],
-        v28: vreg = ["v28", "b28", "h28", "s28", "d28", "q28", "z28"],
-        v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29", "z29"],
-        v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30", "z30"],
-        v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31", "z31"],
+        v16: vreg = ["v16", "b16", "h16", "s16", "d16", "q16", "z16"] % restricted_for_arm64ec,
+        v17: vreg = ["v17", "b17", "h17", "s17", "d17", "q17", "z17"] % restricted_for_arm64ec,
+        v18: vreg = ["v18", "b18", "h18", "s18", "d18", "q18", "z18"] % restricted_for_arm64ec,
+        v19: vreg = ["v19", "b19", "h19", "s19", "d19", "q19", "z19"] % restricted_for_arm64ec,
+        v20: vreg = ["v20", "b20", "h20", "s20", "d20", "q20", "z20"] % restricted_for_arm64ec,
+        v21: vreg = ["v21", "b21", "h21", "s21", "d21", "q21", "z21"] % restricted_for_arm64ec,
+        v22: vreg = ["v22", "b22", "h22", "s22", "d22", "q22", "z22"] % restricted_for_arm64ec,
+        v23: vreg = ["v23", "b23", "h23", "s23", "d23", "q23", "z23"] % restricted_for_arm64ec,
+        v24: vreg = ["v24", "b24", "h24", "s24", "d24", "q24", "z24"] % restricted_for_arm64ec,
+        v25: vreg = ["v25", "b25", "h25", "s25", "d25", "q25", "z25"] % restricted_for_arm64ec,
+        v26: vreg = ["v26", "b26", "h26", "s26", "d26", "q26", "z26"] % restricted_for_arm64ec,
+        v27: vreg = ["v27", "b27", "h27", "s27", "d27", "q27", "z27"] % restricted_for_arm64ec,
+        v28: vreg = ["v28", "b28", "h28", "s28", "d28", "q28", "z28"] % restricted_for_arm64ec,
+        v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29", "z29"] % restricted_for_arm64ec,
+        v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30", "z30"] % restricted_for_arm64ec,
+        v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31", "z31"] % restricted_for_arm64ec,
         p0: preg = ["p0"],
         p1: preg = ["p1"],
         p2: preg = ["p2"],
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 2e04dca98c5..d6bbf4f36cf 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -217,6 +217,7 @@ pub enum InlineAsmArch {
     X86_64,
     Arm,
     AArch64,
+    Arm64EC,
     RiscV32,
     RiscV64,
     Nvptx64,
@@ -246,6 +247,7 @@ impl FromStr for InlineAsmArch {
             "x86_64" => Ok(Self::X86_64),
             "arm" => Ok(Self::Arm),
             "aarch64" => Ok(Self::AArch64),
+            "arm64ec" => Ok(Self::Arm64EC),
             "riscv32" => Ok(Self::RiscV32),
             "riscv64" => Ok(Self::RiscV64),
             "nvptx64" => Ok(Self::Nvptx64),
@@ -341,7 +343,9 @@ impl InlineAsmReg {
         Ok(match arch {
             InlineAsmArch::X86 | InlineAsmArch::X86_64 => Self::X86(X86InlineAsmReg::parse(name)?),
             InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(name)?),
-            InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmReg::parse(name)?),
+            InlineAsmArch::AArch64 | InlineAsmArch::Arm64EC => {
+                Self::AArch64(AArch64InlineAsmReg::parse(name)?)
+            }
             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
                 Self::RiscV(RiscVInlineAsmReg::parse(name)?)
             }
@@ -610,7 +614,9 @@ impl InlineAsmRegClass {
                 Self::X86(X86InlineAsmRegClass::parse(name)?)
             }
             InlineAsmArch::Arm => Self::Arm(ArmInlineAsmRegClass::parse(name)?),
-            InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmRegClass::parse(name)?),
+            InlineAsmArch::AArch64 | InlineAsmArch::Arm64EC => {
+                Self::AArch64(AArch64InlineAsmRegClass::parse(name)?)
+            }
             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
                 Self::RiscV(RiscVInlineAsmRegClass::parse(name)?)
             }
@@ -783,7 +789,7 @@ pub fn allocatable_registers(
             arm::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
             map
         }
-        InlineAsmArch::AArch64 => {
+        InlineAsmArch::AArch64 | InlineAsmArch::Arm64EC => {
             let mut map = aarch64::regclass_map();
             aarch64::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
             map
@@ -909,6 +915,10 @@ impl InlineAsmClobberAbi {
                 }),
                 _ => Err(&["C", "system", "efiapi"]),
             },
+            InlineAsmArch::Arm64EC => match name {
+                "C" | "system" => Ok(InlineAsmClobberAbi::AArch64NoX18),
+                _ => Err(&["C", "system"]),
+            },
             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
                 "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::RiscV),
                 _ => Err(&["C", "system", "efiapi"]),
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 8813955f2af..56ae7ad9f74 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -373,17 +373,8 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
             Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)),
             Pat(t, p) => write!(f, "pattern_type!({:?} is {:?})", &this.wrap(t), &this.wrap(p)),
             Slice(t) => write!(f, "[{:?}]", &this.wrap(t)),
-            RawPtr(ty, mutbl) => {
-                match mutbl {
-                    Mutability::Mut => write!(f, "*mut "),
-                    Mutability::Not => write!(f, "*const "),
-                }?;
-                write!(f, "{:?}", &this.wrap(ty))
-            }
-            Ref(r, t, m) => match m {
-                Mutability::Mut => write!(f, "&{:?} mut {:?}", &this.wrap(r), &this.wrap(t)),
-                Mutability::Not => write!(f, "&{:?} {:?}", &this.wrap(r), &this.wrap(t)),
-            },
+            RawPtr(ty, mutbl) => write!(f, "*{} {:?}", mutbl.ptr_str(), this.wrap(ty)),
+            Ref(r, t, m) => write!(f, "&{:?} {}{:?}", this.wrap(r), m.prefix_str(), this.wrap(t)),
             FnDef(d, s) => f.debug_tuple("FnDef").field(d).field(&this.wrap(s)).finish(),
             FnPtr(s) => write!(f, "{:?}", &this.wrap(s)),
             Dynamic(p, r, repr) => match repr {
diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
index 59acbc73db4..43e11b6d57d 100644
--- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
+++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
@@ -19,6 +19,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 - M68k
 - CSKY
 - s390x
+- Arm64EC
 
 ## Register classes
 
@@ -51,6 +52,9 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `freg`         | `f[0-31]`                          | `f`                  |
 | s390x        | `reg`          | `r[0-10]`, `r[12-14]`              | `r`                  |
 | s390x        | `freg`         | `f[0-15]`                          | `f`                  |
+| Arm64EC      | `reg`          | `x[0-12]`, `x[15-22]`, `x[25-27]`, `x30` | `r`            |
+| Arm64EC      | `vreg`         | `v[0-15]`                          | `w`                  |
+| Arm64EC      | `vreg_low16`   | `v[0-15]`                          | `x`                  |
 
 > **Notes**:
 > - NVPTX doesn't have a fixed register set, so named registers are not supported.
@@ -86,6 +90,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `freg`                          | None           | `f32`,                                  |
 | s390x        | `reg`, `reg_addr`               | None           | `i8`, `i16`, `i32`, `i64`               |
 | s390x        | `freg`                          | None           | `f32`, `f64`                            |
+| Arm64EC      | `reg`                           | None           | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
+| Arm64EC      | `vreg`                          | None           | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`, <br> `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |
 
 ## Register aliases
 
@@ -118,6 +124,12 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `r29`         | `rtb`     |
 | CSKY         | `r30`         | `svbr`    |
 | CSKY         | `r31`         | `tls`     |
+| Arm64EC      | `x[0-30]`     | `w[0-30]` |
+| Arm64EC      | `x29`         | `fp`      |
+| Arm64EC      | `x30`         | `lr`      |
+| Arm64EC      | `sp`          | `wsp`     |
+| Arm64EC      | `xzr`         | `wzr`     |
+| Arm64EC      | `v[0-15]`     | `b[0-15]`, `h[0-15]`, `s[0-15]`, `d[0-15]`, `q[0-15]` |
 
 > **Notes**:
 > - TI does not mandate a frame pointer for MSP430, but toolchains are allowed
@@ -128,8 +140,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | Architecture | Unsupported register                    | Reason                                                                                                                                                                              |
 | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 | All          | `sp`, `r15` (s390x)                     | The stack pointer must be restored to its original value at the end of an asm code block.                                                                                           |
-| All          | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x) | The frame pointer cannot be used as an input or output.                                                                                                                             |
-| All          | `r19` (Hexagon)                         | This is used internally by LLVM as a "base pointer" for functions with complex stack frames.                                                                                        |
+| All          | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output.                                                                                                                             |
+| All          | `r19` (Hexagon), `x19` (Arm64EC)        | This is used internally by LLVM as a "base pointer" for functions with complex stack frames.                                                                                        |
 | MIPS         | `$0` or `$zero`                         | This is a constant zero register which can't be modified.                                                                                                                           |
 | MIPS         | `$1` or `$at`                           | Reserved for assembler.                                                                                                                                                             |
 | MIPS         | `$26`/`$k0`, `$27`/`$k1`                | OS-reserved registers.                                                                                                                                                              |
@@ -145,6 +157,9 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `r15`                                   | This is the link register. |
 | CSKY         | `r[26-30]`                              | Reserved by its ABI.       |
 | CSKY         | `r31`                                   | This is the TLS register.  |
+| Arm64EC      | `xzr`                                   | This is a constant zero register which can't be modified. |
+| Arm64EC      | `x18`                                   | This is an OS-reserved register. |
+| Arm64EC      | `x13`, `x14`, `x23`, `x24`, `x28`, `v[16-31]` | These are AArch64 registers that are not supported for Arm64EC. |
 
 
 ## Template modifiers
@@ -165,6 +180,16 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | s390x        | `freg`         | None     | `%f0`          | None          |
 | CSKY         | `reg`          | None     | `r0`           | None          |
 | CSKY         | `freg`         | None     | `f0`           | None          |
+| Arm64EC      | `reg`          | None     | `x0`           | `x`           |
+| Arm64EC      | `reg`          | `w`      | `w0`           | `w`           |
+| Arm64EC      | `reg`          | `x`      | `x0`           | `x`           |
+| Arm64EC      | `vreg`         | None     | `v0`           | None          |
+| Arm64EC      | `vreg`         | `v`      | `v0`           | None          |
+| Arm64EC      | `vreg`         | `b`      | `b0`           | `b`           |
+| Arm64EC      | `vreg`         | `h`      | `h0`           | `h`           |
+| Arm64EC      | `vreg`         | `s`      | `s0`           | `s`           |
+| Arm64EC      | `vreg`         | `d`      | `d0`           | `d`           |
+| Arm64EC      | `vreg`         | `q`      | `q0`           | `q`           |
 
 # Flags covered by `preserves_flags`
 
@@ -177,3 +202,6 @@ These flags registers must be restored upon exiting the asm block if the `preser
   - The condition code register `ccr`.
 - s390x
   - The condition code register `cc`.
+- Arm64EC
+  - Condition flags (`NZCV` register).
+  - Floating-point status (`FPSR` register).
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index ec944cb7fb4..80dd06dc7ad 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -935,16 +935,25 @@ struct HeaderLine<'ln> {
 pub(crate) struct CheckDirectiveResult<'ln> {
     is_known_directive: bool,
     directive_name: &'ln str,
+    trailing_directive: Option<&'ln str>,
 }
 
-// Returns `(is_known_directive, directive_name)`.
 pub(crate) fn check_directive(directive_ln: &str) -> CheckDirectiveResult<'_> {
-    let directive_name =
-        directive_ln.split_once([':', ' ']).map(|(pre, _)| pre).unwrap_or(directive_ln);
+    let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, ""));
+
+    let trailing = post.trim().split_once(' ').map(|(pre, _)| pre).unwrap_or(post);
+    let trailing_directive = {
+        // 1. is the directive name followed by a space? (to exclude `:`)
+        matches!(directive_ln.get(directive_name.len()..), Some(s) if s.starts_with(" "))
+            // 2. is what is after that directive also a directive (ex: "only-x86 only-arm")
+            && KNOWN_DIRECTIVE_NAMES.contains(&trailing)
+    }
+    .then_some(trailing);
 
     CheckDirectiveResult {
         is_known_directive: KNOWN_DIRECTIVE_NAMES.contains(&directive_name),
         directive_name: directive_ln,
+        trailing_directive,
     }
 }
 
@@ -1014,7 +1023,8 @@ fn iter_header(
             if testfile.extension().map(|e| e == "rs").unwrap_or(false) {
                 let directive_ln = non_revisioned_directive_line.trim();
 
-                let CheckDirectiveResult { is_known_directive, .. } = check_directive(directive_ln);
+                let CheckDirectiveResult { is_known_directive, trailing_directive, .. } =
+                    check_directive(directive_ln);
 
                 if !is_known_directive {
                     *poisoned = true;
@@ -1028,6 +1038,21 @@ fn iter_header(
 
                     return;
                 }
+
+                if let Some(trailing_directive) = &trailing_directive {
+                    *poisoned = true;
+
+                    eprintln!(
+                        "error: detected trailing compiletest test directive `{}` in {}:{}\n \
+                          help: put the trailing directive in it's own line: `//@ {}`",
+                        trailing_directive,
+                        testfile.display(),
+                        line_number,
+                        trailing_directive,
+                    );
+
+                    return;
+                }
             }
 
             it(HeaderLine {
@@ -1051,7 +1076,8 @@ fn iter_header(
 
             let rest = rest.trim_start();
 
-            let CheckDirectiveResult { is_known_directive, directive_name } = check_directive(rest);
+            let CheckDirectiveResult { is_known_directive, directive_name, .. } =
+                check_directive(rest);
 
             if is_known_directive {
                 *poisoned = true;
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index 83f0755b5c8..8a37a4d6d31 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -667,3 +667,24 @@ fn test_non_rs_unknown_directive_not_checked() {
     );
     assert!(!poisoned);
 }
+
+#[test]
+fn test_trailing_directive() {
+    let mut poisoned = false;
+    run_path(&mut poisoned, Path::new("a.rs"), b"//@ only-x86 only-arm");
+    assert!(poisoned);
+}
+
+#[test]
+fn test_trailing_directive_with_comment() {
+    let mut poisoned = false;
+    run_path(&mut poisoned, Path::new("a.rs"), b"//@ only-x86   only-arm with comment");
+    assert!(poisoned);
+}
+
+#[test]
+fn test_not_trailing_directive() {
+    let mut poisoned = false;
+    run_path(&mut poisoned, Path::new("a.rs"), b"//@ revisions: incremental");
+    assert!(!poisoned);
+}
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index e14932ad99d..211dc347b0f 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -1791,7 +1791,6 @@ ui/issues/issue-2150.rs
 ui/issues/issue-2151.rs
 ui/issues/issue-21546.rs
 ui/issues/issue-21554.rs
-ui/issues/issue-21596.rs
 ui/issues/issue-21600.rs
 ui/issues/issue-21622.rs
 ui/issues/issue-21634.rs
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 78de8c0537d..7136bc4d8f2 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -17,7 +17,7 @@ use std::path::{Path, PathBuf};
 const ENTRY_LIMIT: usize = 900;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: usize = 1722;
+const ISSUES_ENTRY_LIMIT: usize = 1720;
 const ROOT_ENTRY_LIMIT: usize = 859;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
diff --git a/tests/assembly/asm/aarch64-types.rs b/tests/assembly/asm/aarch64-types.rs
index 1b2bd4b3d81..3e2a4773703 100644
--- a/tests/assembly/asm/aarch64-types.rs
+++ b/tests/assembly/asm/aarch64-types.rs
@@ -1,8 +1,11 @@
+//@ revisions: aarch64 arm64ec
 //@ assembly-output: emit-asm
-//@ compile-flags: --target aarch64-unknown-linux-gnu
-//@ needs-llvm-components: aarch64
+//@ [aarch64] compile-flags: --target aarch64-unknown-linux-gnu
+//@ [aarch64] needs-llvm-components: aarch64
+//@ [arm64ec] compile-flags: --target arm64ec-pc-windows-msvc
+//@ [arm64ec] needs-llvm-components: aarch64
 
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_experimental_arch)]
 #![crate_type = "rlib"]
 #![no_core]
 #![allow(asm_sub_register, non_camel_case_types)]
@@ -77,7 +80,7 @@ extern "C" {
     static extern_static: u8;
 }
 
-// CHECK-LABEL: sym_fn:
+// CHECK-LABEL: {{("#)?}}sym_fn{{"?}}
 // CHECK: //APP
 // CHECK: bl extern_func
 // CHECK: //NO_APP
@@ -86,7 +89,7 @@ pub unsafe fn sym_fn() {
     asm!("bl {}", sym extern_func);
 }
 
-// CHECK-LABEL: sym_static:
+// CHECK-LABEL: {{("#)?}}sym_static{{"?}}
 // CHECK: //APP
 // CHECK: adr x0, extern_static
 // CHECK: //NO_APP
@@ -96,7 +99,7 @@ pub unsafe fn sym_static() {
 }
 
 // Regression test for #75761
-// CHECK-LABEL: issue_75761:
+// CHECK-LABEL: {{("#)?}}issue_75761{{"?}}
 // CHECK: str {{.*}}x30
 // CHECK: //APP
 // CHECK: //NO_APP
@@ -144,421 +147,421 @@ macro_rules! check_reg {
     };
 }
 
-// CHECK-LABEL: reg_i8:
+// CHECK-LABEL: {{("#)?}}reg_i8{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check!(reg_i8 i8 reg "mov" "");
 
-// CHECK-LABEL: reg_i16:
+// CHECK-LABEL: {{("#)?}}reg_i16{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check!(reg_i16 i16 reg "mov" "");
 
-// CHECK-LABEL: reg_i32:
+// CHECK-LABEL: {{("#)?}}reg_i32{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check!(reg_i32 i32 reg "mov" "");
 
-// CHECK-LABEL: reg_f32:
+// CHECK-LABEL: {{("#)?}}reg_f32{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check!(reg_f32 f32 reg "mov" "");
 
-// CHECK-LABEL: reg_i64:
+// CHECK-LABEL: {{("#)?}}reg_i64{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check!(reg_i64 i64 reg "mov" "");
 
-// CHECK-LABEL: reg_f64:
+// CHECK-LABEL: {{("#)?}}reg_f64{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check!(reg_f64 f64 reg "mov" "");
 
-// CHECK-LABEL: reg_ptr:
+// CHECK-LABEL: {{("#)?}}reg_ptr{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check!(reg_ptr ptr reg "mov" "");
 
-// CHECK-LABEL: vreg_i8:
+// CHECK-LABEL: {{("#)?}}vreg_i8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i8 i8 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i16:
+// CHECK-LABEL: {{("#)?}}vreg_i16{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i16 i16 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i32:
+// CHECK-LABEL: {{("#)?}}vreg_i32{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i32 i32 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_f32:
+// CHECK-LABEL: {{("#)?}}vreg_f32{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_f32 f32 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i64:
+// CHECK-LABEL: {{("#)?}}vreg_i64{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i64 i64 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_f64:
+// CHECK-LABEL: {{("#)?}}vreg_f64{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_f64 f64 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_ptr:
+// CHECK-LABEL: {{("#)?}}vreg_ptr{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_ptr ptr vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i8x8:
+// CHECK-LABEL: {{("#)?}}vreg_i8x8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i8x8 i8x8 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i16x4:
+// CHECK-LABEL: {{("#)?}}vreg_i16x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i16x4 i16x4 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i32x2:
+// CHECK-LABEL: {{("#)?}}vreg_i32x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i32x2 i32x2 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i64x1:
+// CHECK-LABEL: {{("#)?}}vreg_i64x1{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i64x1 i64x1 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_f32x2:
+// CHECK-LABEL: {{("#)?}}vreg_f32x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_f32x2 f32x2 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_f64x1:
+// CHECK-LABEL: {{("#)?}}vreg_f64x1{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_f64x1 f64x1 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i8x16:
+// CHECK-LABEL: {{("#)?}}vreg_i8x16{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i8x16 i8x16 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i16x8:
+// CHECK-LABEL: {{("#)?}}vreg_i16x8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i16x8 i16x8 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i32x4:
+// CHECK-LABEL: {{("#)?}}vreg_i32x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i32x4 i32x4 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_i64x2:
+// CHECK-LABEL: {{("#)?}}vreg_i64x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_i64x2 i64x2 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_f32x4:
+// CHECK-LABEL: {{("#)?}}vreg_f32x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_f32x4 f32x4 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_f64x2:
+// CHECK-LABEL: {{("#)?}}vreg_f64x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_f64x2 f64x2 vreg "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i8:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i8 i8 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i16:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i16{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i16 i16 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_f32:
+// CHECK-LABEL: {{("#)?}}vreg_low16_f32{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_f32 f32 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i64:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i64{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i64 i64 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_f64:
+// CHECK-LABEL: {{("#)?}}vreg_low16_f64{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_f64 f64 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_ptr:
+// CHECK-LABEL: {{("#)?}}vreg_low16_ptr{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_ptr ptr vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i8x8:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i8x8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i8x8 i8x8 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i16x4:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i16x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i16x4 i16x4 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i32x2:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i32x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i32x2 i32x2 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i64x1:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i64x1{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i64x1 i64x1 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_f32x2:
+// CHECK-LABEL: {{("#)?}}vreg_low16_f32x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_f32x2 f32x2 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_f64x1:
+// CHECK-LABEL: {{("#)?}}vreg_low16_f64x1{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_f64x1 f64x1 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i8x16:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i8x16{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i8x16 i8x16 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i16x8:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i16x8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i16x8 i16x8 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i32x4:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i32x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i32x4 i32x4 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_i64x2:
+// CHECK-LABEL: {{("#)?}}vreg_low16_i64x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_i64x2 i64x2 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_f32x4:
+// CHECK-LABEL: {{("#)?}}vreg_low16_f32x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_f32x4 f32x4 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: vreg_low16_f64x2:
+// CHECK-LABEL: {{("#)?}}vreg_low16_f64x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}}
 // CHECK: //NO_APP
 check!(vreg_low16_f64x2 f64x2 vreg_low16 "fmov" "s");
 
-// CHECK-LABEL: x0_i8:
+// CHECK-LABEL: {{("#)?}}x0_i8{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check_reg!(x0_i8 i8 "x0" "mov");
 
-// CHECK-LABEL: x0_i16:
+// CHECK-LABEL: {{("#)?}}x0_i16{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check_reg!(x0_i16 i16 "x0" "mov");
 
-// CHECK-LABEL: x0_i32:
+// CHECK-LABEL: {{("#)?}}x0_i32{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check_reg!(x0_i32 i32 "x0" "mov");
 
-// CHECK-LABEL: x0_f32:
+// CHECK-LABEL: {{("#)?}}x0_f32{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check_reg!(x0_f32 f32 "x0" "mov");
 
-// CHECK-LABEL: x0_i64:
+// CHECK-LABEL: {{("#)?}}x0_i64{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check_reg!(x0_i64 i64 "x0" "mov");
 
-// CHECK-LABEL: x0_f64:
+// CHECK-LABEL: {{("#)?}}x0_f64{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check_reg!(x0_f64 f64 "x0" "mov");
 
-// CHECK-LABEL: x0_ptr:
+// CHECK-LABEL: {{("#)?}}x0_ptr{{"?}}
 // CHECK: //APP
 // CHECK: mov x{{[0-9]+}}, x{{[0-9]+}}
 // CHECK: //NO_APP
 check_reg!(x0_ptr ptr "x0" "mov");
 
-// CHECK-LABEL: v0_i8:
+// CHECK-LABEL: {{("#)?}}v0_i8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i8 i8 "s0" "fmov");
 
-// CHECK-LABEL: v0_i16:
+// CHECK-LABEL: {{("#)?}}v0_i16{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i16 i16 "s0" "fmov");
 
-// CHECK-LABEL: v0_i32:
+// CHECK-LABEL: {{("#)?}}v0_i32{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i32 i32 "s0" "fmov");
 
-// CHECK-LABEL: v0_f32:
+// CHECK-LABEL: {{("#)?}}v0_f32{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_f32 f32 "s0" "fmov");
 
-// CHECK-LABEL: v0_i64:
+// CHECK-LABEL: {{("#)?}}v0_i64{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i64 i64 "s0" "fmov");
 
-// CHECK-LABEL: v0_f64:
+// CHECK-LABEL: {{("#)?}}v0_f64{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_f64 f64 "s0" "fmov");
 
-// CHECK-LABEL: v0_ptr:
+// CHECK-LABEL: {{("#)?}}v0_ptr{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_ptr ptr "s0" "fmov");
 
-// CHECK-LABEL: v0_i8x8:
+// CHECK-LABEL: {{("#)?}}v0_i8x8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i8x8 i8x8 "s0" "fmov");
 
-// CHECK-LABEL: v0_i16x4:
+// CHECK-LABEL: {{("#)?}}v0_i16x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i16x4 i16x4 "s0" "fmov");
 
-// CHECK-LABEL: v0_i32x2:
+// CHECK-LABEL: {{("#)?}}v0_i32x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i32x2 i32x2 "s0" "fmov");
 
-// CHECK-LABEL: v0_i64x1:
+// CHECK-LABEL: {{("#)?}}v0_i64x1{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i64x1 i64x1 "s0" "fmov");
 
-// CHECK-LABEL: v0_f32x2:
+// CHECK-LABEL: {{("#)?}}v0_f32x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_f32x2 f32x2 "s0" "fmov");
 
-// CHECK-LABEL: v0_f64x1:
+// CHECK-LABEL: {{("#)?}}v0_f64x1{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_f64x1 f64x1 "s0" "fmov");
 
-// CHECK-LABEL: v0_i8x16:
+// CHECK-LABEL: {{("#)?}}v0_i8x16{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i8x16 i8x16 "s0" "fmov");
 
-// CHECK-LABEL: v0_i16x8:
+// CHECK-LABEL: {{("#)?}}v0_i16x8{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i16x8 i16x8 "s0" "fmov");
 
-// CHECK-LABEL: v0_i32x4:
+// CHECK-LABEL: {{("#)?}}v0_i32x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i32x4 i32x4 "s0" "fmov");
 
-// CHECK-LABEL: v0_i64x2:
+// CHECK-LABEL: {{("#)?}}v0_i64x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_i64x2 i64x2 "s0" "fmov");
 
-// CHECK-LABEL: v0_f32x4:
+// CHECK-LABEL: {{("#)?}}v0_f32x4{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
 check_reg!(v0_f32x4 f32x4 "s0" "fmov");
 
-// CHECK-LABEL: v0_f64x2:
+// CHECK-LABEL: {{("#)?}}v0_f64x2{{"?}}
 // CHECK: //APP
 // CHECK: fmov s0, s0
 // CHECK: //NO_APP
diff --git a/tests/ui/asm/aarch64/type-check-2-2.stderr b/tests/ui/asm/aarch64/type-check-2-2.stderr
index 41f7c01dc82..760aaefac83 100644
--- a/tests/ui/asm/aarch64/type-check-2-2.stderr
+++ b/tests/ui/asm/aarch64/type-check-2-2.stderr
@@ -8,8 +8,8 @@ LL |         asm!("{}", in(reg) x);
    |
 help: consider assigning a value
    |
-LL |         let x: u64 = 0;
-   |                    +++
+LL |         let x: u64 = 42;
+   |                    ++++
 
 error[E0381]: used binding `y` isn't initialized
   --> $DIR/type-check-2-2.rs:22:9
@@ -21,8 +21,8 @@ LL |         asm!("{}", inout(reg) y);
    |
 help: consider assigning a value
    |
-LL |         let mut y: u64 = 0;
-   |                        +++
+LL |         let mut y: u64 = 42;
+   |                        ++++
 
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
   --> $DIR/type-check-2-2.rs:28:13
diff --git a/tests/ui/asm/x86_64/type-check-5.stderr b/tests/ui/asm/x86_64/type-check-5.stderr
index 7970e76d6a1..4fb75993463 100644
--- a/tests/ui/asm/x86_64/type-check-5.stderr
+++ b/tests/ui/asm/x86_64/type-check-5.stderr
@@ -8,8 +8,8 @@ LL |         asm!("{}", in(reg) x);
    |
 help: consider assigning a value
    |
-LL |         let x: u64 = 0;
-   |                    +++
+LL |         let x: u64 = 42;
+   |                    ++++
 
 error[E0381]: used binding `y` isn't initialized
   --> $DIR/type-check-5.rs:18:9
@@ -21,8 +21,8 @@ LL |         asm!("{}", inout(reg) y);
    |
 help: consider assigning a value
    |
-LL |         let mut y: u64 = 0;
-   |                        +++
+LL |         let mut y: u64 = 42;
+   |                        ++++
 
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
   --> $DIR/type-check-5.rs:24:13
diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs
index 1990d0ffe2a..ffb97ca04ac 100644
--- a/tests/ui/async-await/async-borrowck-escaping-closure-error.rs
+++ b/tests/ui/async-await/async-borrowck-escaping-closure-error.rs
@@ -5,7 +5,6 @@ fn foo() -> Box<dyn std::future::Future<Output = u32>> {
     let x = 0u32;
     Box::new((async || x)())
     //~^ ERROR cannot return value referencing local variable `x`
-    //~| ERROR cannot return value referencing temporary value
 }
 
 fn main() {
diff --git a/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr b/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr
index be67c78221a..4b1ce300b56 100644
--- a/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr
+++ b/tests/ui/async-await/async-borrowck-escaping-closure-error.stderr
@@ -7,15 +7,6 @@ LL |     Box::new((async || x)())
    |     |        `x` is borrowed here
    |     returns a value referencing data owned by the current function
 
-error[E0515]: cannot return value referencing temporary value
-  --> $DIR/async-borrowck-escaping-closure-error.rs:6:5
-   |
-LL |     Box::new((async || x)())
-   |     ^^^^^^^^^------------^^^
-   |     |        |
-   |     |        temporary value created here
-   |     returns a value referencing data owned by the current function
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0515`.
diff --git a/tests/ui/async-await/async-closures/moro-example.rs b/tests/ui/async-await/async-closures/moro-example.rs
new file mode 100644
index 00000000000..5a8f42c7ca5
--- /dev/null
+++ b/tests/ui/async-await/async-closures/moro-example.rs
@@ -0,0 +1,43 @@
+//@ check-pass
+//@ edition: 2021
+
+#![feature(async_closure)]
+
+use std::future::Future;
+use std::pin::Pin;
+use std::{marker::PhantomData, sync::Mutex};
+
+type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
+
+pub struct Scope<'scope, 'env: 'scope> {
+    enqueued: Mutex<Vec<BoxFuture<'scope, ()>>>,
+    phantom: PhantomData<&'env ()>,
+}
+
+impl<'scope, 'env: 'scope> Scope<'scope, 'env> {
+    pub fn spawn(&'scope self, future: impl Future<Output = ()> + Send + 'scope) {
+        self.enqueued.lock().unwrap().push(Box::pin(future));
+    }
+}
+
+fn scope_with_closure<'env, B>(_body: B) -> BoxFuture<'env, ()>
+where
+    for<'scope> B: async FnOnce(&'scope Scope<'scope, 'env>),
+{
+    todo!()
+}
+
+type ScopeRef<'scope, 'env> = &'scope Scope<'scope, 'env>;
+
+async fn go<'a>(value: &'a i32) {
+    let closure = async |scope: ScopeRef<'_, 'a>| {
+        let _future1 = scope.spawn(async {
+            // Make sure that `*value` is immutably borrowed with lifetime of
+            // `'a` and not with the lifetime of the containing coroutine-closure.
+            let _v = *value;
+        });
+    };
+    scope_with_closure(closure).await;
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/async-closures/no-borrow-from-env.rs b/tests/ui/async-await/async-closures/no-borrow-from-env.rs
new file mode 100644
index 00000000000..fe84aeeb32f
--- /dev/null
+++ b/tests/ui/async-await/async-closures/no-borrow-from-env.rs
@@ -0,0 +1,44 @@
+//@ edition: 2021
+//@ check-pass
+
+#![feature(async_closure)]
+
+fn outlives<'a>(_: impl Sized + 'a) {}
+
+async fn call_once(f: impl async FnOnce()) {
+    f().await;
+}
+
+fn simple<'a>(x: &'a i32) {
+    let c = async || { println!("{}", *x); };
+    outlives::<'a>(c());
+    outlives::<'a>(call_once(c));
+
+    let c = async move || { println!("{}", *x); };
+    outlives::<'a>(c());
+    outlives::<'a>(call_once(c));
+}
+
+struct S<'a>(&'a i32);
+
+fn through_field<'a>(x: S<'a>) {
+    let c = async || { println!("{}", *x.0); };
+    outlives::<'a>(c());
+    outlives::<'a>(call_once(c));
+
+    let c = async move || { println!("{}", *x.0); };
+    outlives::<'a>(c());
+    outlives::<'a>(call_once(c));
+}
+
+fn through_field_and_ref<'a>(x: &S<'a>) {
+    let c = async || { println!("{}", *x.0); };
+    outlives::<'a>(c());
+    outlives::<'a>(call_once(c));
+
+    let c = async move || { println!("{}", *x.0); };
+    outlives::<'a>(c());
+    // outlives::<'a>(call_once(c)); // FIXME(async_closures): Figure out why this fails
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.rs b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.rs
new file mode 100644
index 00000000000..17681161e20
--- /dev/null
+++ b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.rs
@@ -0,0 +1,47 @@
+//@ edition: 2018
+
+// This is `no-borrow-from-env.rs`, but under edition 2018 we still want to make
+// sure that we don't ICE or anything, even if precise closure captures means
+// that we can't actually borrowck successfully.
+
+#![feature(async_closure)]
+
+fn outlives<'a>(_: impl Sized + 'a) {}
+
+async fn call_once(f: impl async FnOnce()) {
+    f().await;
+}
+
+fn simple<'a>(x: &'a i32) {
+    let c = async || { println!("{}", *x); }; //~ ERROR `x` does not live long enough
+    outlives::<'a>(c());
+    outlives::<'a>(call_once(c));
+
+    let c = async move || { println!("{}", *x); };
+    outlives::<'a>(c()); //~ ERROR `c` does not live long enough
+    outlives::<'a>(call_once(c)); //~ ERROR cannot move out of `c`
+}
+
+struct S<'a>(&'a i32);
+
+fn through_field<'a>(x: S<'a>) {
+    let c = async || { println!("{}", *x.0); }; //~ ERROR `x` does not live long enough
+    outlives::<'a>(c());
+    outlives::<'a>(call_once(c));
+
+    let c = async move || { println!("{}", *x.0); }; //~ ERROR cannot move out of `x`
+    outlives::<'a>(c()); //~ ERROR `c` does not live long enough
+    outlives::<'a>(call_once(c)); //~ ERROR cannot move out of `c`
+}
+
+fn through_field_and_ref<'a>(x: &S<'a>) {
+    let c = async || { println!("{}", *x.0); }; //~ ERROR `x` does not live long enough
+    outlives::<'a>(c());
+    outlives::<'a>(call_once(c)); //~ ERROR explicit lifetime required in the type of `x`
+
+    let c = async move || { println!("{}", *x.0); };
+    outlives::<'a>(c()); //~ ERROR `c` does not live long enough
+    // outlives::<'a>(call_once(c)); // FIXME(async_closures): Figure out why this fails
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr
new file mode 100644
index 00000000000..569028934cb
--- /dev/null
+++ b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr
@@ -0,0 +1,152 @@
+error[E0597]: `x` does not live long enough
+  --> $DIR/without-precise-captures-we-are-powerless.rs:16:13
+   |
+LL | fn simple<'a>(x: &'a i32) {
+   |           -- lifetime `'a` defined here
+LL |     let c = async || { println!("{}", *x); };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+LL |     outlives::<'a>(c());
+LL |     outlives::<'a>(call_once(c));
+   |                    ------------ argument requires that `x` is borrowed for `'a`
+...
+LL | }
+   |  - `x` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/without-precise-captures-we-are-powerless.rs:21:20
+   |
+LL | fn simple<'a>(x: &'a i32) {
+   |           -- lifetime `'a` defined here
+...
+LL |     let c = async move || { println!("{}", *x); };
+   |         - binding `c` declared here
+LL |     outlives::<'a>(c());
+   |                    ^--
+   |                    |
+   |                    borrowed value does not live long enough
+   |                    argument requires that `c` is borrowed for `'a`
+LL |     outlives::<'a>(call_once(c));
+LL | }
+   | - `c` dropped here while still borrowed
+
+error[E0505]: cannot move out of `c` because it is borrowed
+  --> $DIR/without-precise-captures-we-are-powerless.rs:22:30
+   |
+LL | fn simple<'a>(x: &'a i32) {
+   |           -- lifetime `'a` defined here
+...
+LL |     let c = async move || { println!("{}", *x); };
+   |         - binding `c` declared here
+LL |     outlives::<'a>(c());
+   |                    ---
+   |                    |
+   |                    borrow of `c` occurs here
+   |                    argument requires that `c` is borrowed for `'a`
+LL |     outlives::<'a>(call_once(c));
+   |                              ^ move out of `c` occurs here
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/without-precise-captures-we-are-powerless.rs:28:13
+   |
+LL | fn through_field<'a>(x: S<'a>) {
+   |                  -- lifetime `'a` defined here
+LL |     let c = async || { println!("{}", *x.0); };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+LL |     outlives::<'a>(c());
+LL |     outlives::<'a>(call_once(c));
+   |                    ------------ argument requires that `x` is borrowed for `'a`
+...
+LL | }
+   |  - `x` dropped here while still borrowed
+
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/without-precise-captures-we-are-powerless.rs:32:13
+   |
+LL | fn through_field<'a>(x: S<'a>) {
+   |                  -- lifetime `'a` defined here
+LL |     let c = async || { println!("{}", *x.0); };
+   |             ---------------------------------- borrow of `x` occurs here
+LL |     outlives::<'a>(c());
+LL |     outlives::<'a>(call_once(c));
+   |                    ------------ argument requires that `x` is borrowed for `'a`
+LL |
+LL |     let c = async move || { println!("{}", *x.0); };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move out of `x` occurs here
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/without-precise-captures-we-are-powerless.rs:33:20
+   |
+LL | fn through_field<'a>(x: S<'a>) {
+   |                  -- lifetime `'a` defined here
+...
+LL |     let c = async move || { println!("{}", *x.0); };
+   |         - binding `c` declared here
+LL |     outlives::<'a>(c());
+   |                    ^--
+   |                    |
+   |                    borrowed value does not live long enough
+   |                    argument requires that `c` is borrowed for `'a`
+LL |     outlives::<'a>(call_once(c));
+LL | }
+   | - `c` dropped here while still borrowed
+
+error[E0505]: cannot move out of `c` because it is borrowed
+  --> $DIR/without-precise-captures-we-are-powerless.rs:34:30
+   |
+LL | fn through_field<'a>(x: S<'a>) {
+   |                  -- lifetime `'a` defined here
+...
+LL |     let c = async move || { println!("{}", *x.0); };
+   |         - binding `c` declared here
+LL |     outlives::<'a>(c());
+   |                    ---
+   |                    |
+   |                    borrow of `c` occurs here
+   |                    argument requires that `c` is borrowed for `'a`
+LL |     outlives::<'a>(call_once(c));
+   |                              ^ move out of `c` occurs here
+
+error[E0597]: `x` does not live long enough
+  --> $DIR/without-precise-captures-we-are-powerless.rs:38:13
+   |
+LL | fn through_field_and_ref<'a>(x: &S<'a>) {
+   |                          -- lifetime `'a` defined here
+LL |     let c = async || { println!("{}", *x.0); };
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
+LL |     outlives::<'a>(c());
+LL |     outlives::<'a>(call_once(c));
+   |                    ------------ argument requires that `x` is borrowed for `'a`
+...
+LL | }
+   |  - `x` dropped here while still borrowed
+
+error[E0621]: explicit lifetime required in the type of `x`
+  --> $DIR/without-precise-captures-we-are-powerless.rs:40:20
+   |
+LL | fn through_field_and_ref<'a>(x: &S<'a>) {
+   |                                 ------ help: add explicit lifetime `'a` to the type of `x`: `&'a S<'a>`
+...
+LL |     outlives::<'a>(call_once(c));
+   |                    ^^^^^^^^^^^^ lifetime `'a` required
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/without-precise-captures-we-are-powerless.rs:43:20
+   |
+LL | fn through_field_and_ref<'a>(x: &S<'a>) {
+   |                          -- lifetime `'a` defined here
+...
+LL |     let c = async move || { println!("{}", *x.0); };
+   |         - binding `c` declared here
+LL |     outlives::<'a>(c());
+   |                    ^--
+   |                    |
+   |                    borrowed value does not live long enough
+   |                    argument requires that `c` is borrowed for `'a`
+LL |     // outlives::<'a>(call_once(c)); // FIXME(async_closures): Figure out why this fails
+LL | }
+   | - `c` dropped here while still borrowed
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0505, E0597, E0621.
+For more information about an error, try `rustc --explain E0505`.
diff --git a/tests/ui/binop/issue-77910-1.stderr b/tests/ui/binop/issue-77910-1.stderr
index 6402e568188..74deac900d4 100644
--- a/tests/ui/binop/issue-77910-1.stderr
+++ b/tests/ui/binop/issue-77910-1.stderr
@@ -32,8 +32,8 @@ LL |     xs
    |
 help: consider assigning a value
    |
-LL |     let xs = todo!();
-   |            +++++++++
+LL |     let xs = &42;
+   |            +++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/binop/issue-77910-2.stderr b/tests/ui/binop/issue-77910-2.stderr
index a14560ff188..7087f2cdf41 100644
--- a/tests/ui/binop/issue-77910-2.stderr
+++ b/tests/ui/binop/issue-77910-2.stderr
@@ -21,8 +21,8 @@ LL |     xs
    |
 help: consider assigning a value
    |
-LL |     let xs = todo!();
-   |            +++++++++
+LL |     let xs = &42;
+   |            +++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/borrowck/borrowck-block-uninit.stderr b/tests/ui/borrowck/borrowck-block-uninit.stderr
index 07c09f1f443..4db98a7a0dc 100644
--- a/tests/ui/borrowck/borrowck-block-uninit.stderr
+++ b/tests/ui/borrowck/borrowck-block-uninit.stderr
@@ -10,8 +10,8 @@ LL |         println!("{}", x);
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-break-uninit-2.stderr b/tests/ui/borrowck/borrowck-break-uninit-2.stderr
index 7c0cda31c97..e23ca534e74 100644
--- a/tests/ui/borrowck/borrowck-break-uninit-2.stderr
+++ b/tests/ui/borrowck/borrowck-break-uninit-2.stderr
@@ -10,8 +10,8 @@ LL |     println!("{}", x);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-break-uninit.stderr b/tests/ui/borrowck/borrowck-break-uninit.stderr
index 0d879c6fb7d..0367d224f80 100644
--- a/tests/ui/borrowck/borrowck-break-uninit.stderr
+++ b/tests/ui/borrowck/borrowck-break-uninit.stderr
@@ -10,8 +10,8 @@ LL |     println!("{}", x);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr b/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr
index a27b6956b30..bfe3c60a84a 100644
--- a/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr
+++ b/tests/ui/borrowck/borrowck-init-in-called-fn-expr.stderr
@@ -8,8 +8,8 @@ LL |         i
    |
 help: consider assigning a value
    |
-LL |         let i: isize = 0;
-   |                      +++
+LL |         let i: isize = 42;
+   |                      ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr b/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr
index 16f4c40f529..a248a6d85b6 100644
--- a/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr
+++ b/tests/ui/borrowck/borrowck-init-in-fn-expr.stderr
@@ -8,8 +8,8 @@ LL |         i
    |
 help: consider assigning a value
    |
-LL |         let i: isize = 0;
-   |                      +++
+LL |         let i: isize = 42;
+   |                      ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-init-in-fru.stderr b/tests/ui/borrowck/borrowck-init-in-fru.stderr
index f27993e10b4..b5c332a90bc 100644
--- a/tests/ui/borrowck/borrowck-init-in-fru.stderr
+++ b/tests/ui/borrowck/borrowck-init-in-fru.stderr
@@ -8,8 +8,8 @@ LL |     origin = Point { x: 10, ..origin };
    |
 help: consider assigning a value
    |
-LL |     let mut origin: Point = todo!();
-   |                           +++++++++
+LL |     let mut origin: Point = value;
+   |                           +++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-init-op-equal.stderr b/tests/ui/borrowck/borrowck-init-op-equal.stderr
index 241d24341cb..d621c4ab46e 100644
--- a/tests/ui/borrowck/borrowck-init-op-equal.stderr
+++ b/tests/ui/borrowck/borrowck-init-op-equal.stderr
@@ -8,8 +8,8 @@ LL |     v += 1;
    |
 help: consider assigning a value
    |
-LL |     let v: isize = 0;
-   |                  +++
+LL |     let v: isize = 42;
+   |                  ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-init-plus-equal.stderr b/tests/ui/borrowck/borrowck-init-plus-equal.stderr
index 65de6e8bf5d..109321386ba 100644
--- a/tests/ui/borrowck/borrowck-init-plus-equal.stderr
+++ b/tests/ui/borrowck/borrowck-init-plus-equal.stderr
@@ -8,8 +8,8 @@ LL |     v = v + 1;
    |
 help: consider assigning a value
    |
-LL |     let mut v: isize = 0;
-   |                      +++
+LL |     let mut v: isize = 42;
+   |                      ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-return.stderr b/tests/ui/borrowck/borrowck-return.stderr
index a1bc3008ea8..f680b9af4f0 100644
--- a/tests/ui/borrowck/borrowck-return.stderr
+++ b/tests/ui/borrowck/borrowck-return.stderr
@@ -8,8 +8,8 @@ LL |     return x;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-storage-dead.stderr b/tests/ui/borrowck/borrowck-storage-dead.stderr
index a08e2a7b535..5f29c61c7eb 100644
--- a/tests/ui/borrowck/borrowck-storage-dead.stderr
+++ b/tests/ui/borrowck/borrowck-storage-dead.stderr
@@ -8,8 +8,8 @@ LL |         let _ = x + 1;
    |
 help: consider assigning a value
    |
-LL |         let x: i32 = 0;
-   |                    +++
+LL |         let x: i32 = 42;
+   |                    ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-uninit-after-item.stderr b/tests/ui/borrowck/borrowck-uninit-after-item.stderr
index 06bb419aa3b..c6d52a049d2 100644
--- a/tests/ui/borrowck/borrowck-uninit-after-item.stderr
+++ b/tests/ui/borrowck/borrowck-uninit-after-item.stderr
@@ -9,8 +9,8 @@ LL |     baz(bar);
    |
 help: consider assigning a value
    |
-LL |     let bar = 0;
-   |             +++
+LL |     let bar = 42;
+   |             ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr b/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr
index fdbb451bde4..aaa33f08ff5 100644
--- a/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr
+++ b/tests/ui/borrowck/borrowck-uninit-in-assignop.stderr
@@ -8,8 +8,8 @@ LL |     x += 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:9:5
@@ -21,8 +21,8 @@ LL |     x -= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:12:5
@@ -34,8 +34,8 @@ LL |     x *= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:15:5
@@ -47,8 +47,8 @@ LL |     x /= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:18:5
@@ -60,8 +60,8 @@ LL |     x %= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:21:5
@@ -73,8 +73,8 @@ LL |     x ^= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:24:5
@@ -86,8 +86,8 @@ LL |     x &= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:27:5
@@ -99,8 +99,8 @@ LL |     x |= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:30:5
@@ -112,8 +112,8 @@ LL |     x <<= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:33:5
@@ -125,8 +125,8 @@ LL |     x >>= 1;
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error: aborting due to 10 previous errors
 
diff --git a/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr b/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr
index 73fded7545c..d6759b8e1cf 100644
--- a/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr
+++ b/tests/ui/borrowck/borrowck-uninit-ref-chain.stderr
@@ -8,8 +8,8 @@ LL |     let _y = &**x;
    |
 help: consider assigning a value
    |
-LL |     let x: &&Box<i32> = todo!();
-   |                       +++++++++
+LL |     let x: &&Box<i32> = &&Box::new(42);
+   |                       ++++++++++++++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-ref-chain.rs:11:14
@@ -21,7 +21,7 @@ LL |     let _y = &**x;
    |
 help: consider assigning a value
    |
-LL |     let x: &&S<i32, i32> = todo!();
+LL |     let x: &&S<i32, i32> = &&value;
    |                          +++++++++
 
 error[E0381]: used binding `x` isn't initialized
@@ -34,8 +34,8 @@ LL |     let _y = &**x;
    |
 help: consider assigning a value
    |
-LL |     let x: &&i32 = todo!();
-   |                  +++++++++
+LL |     let x: &&i32 = &&42;
+   |                  ++++++
 
 error[E0381]: partially assigned binding `a` isn't fully initialized
   --> $DIR/borrowck-uninit-ref-chain.rs:18:5
diff --git a/tests/ui/borrowck/borrowck-uninit.stderr b/tests/ui/borrowck/borrowck-uninit.stderr
index 1e004baa143..9538baeafd1 100644
--- a/tests/ui/borrowck/borrowck-uninit.stderr
+++ b/tests/ui/borrowck/borrowck-uninit.stderr
@@ -8,8 +8,8 @@ LL |     foo(x);
    |
 help: consider assigning a value
    |
-LL |     let x: isize = 0;
-   |                  +++
+LL |     let x: isize = 42;
+   |                  ++++
 
 error[E0381]: used binding `a` isn't initialized
   --> $DIR/borrowck-uninit.rs:14:32
diff --git a/tests/ui/borrowck/borrowck-use-in-index-lvalue.fixed b/tests/ui/borrowck/borrowck-use-in-index-lvalue.fixed
new file mode 100644
index 00000000000..947c7f5b744
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-use-in-index-lvalue.fixed
@@ -0,0 +1,11 @@
+//@ run-rustfix
+#[allow(unused_mut)]
+fn test() {
+    let w: &mut [isize] = &mut [];
+    w[5] = 0; //~ ERROR [E0381]
+
+    let mut w: &mut [isize] = &mut [];
+    w[5] = 0; //~ ERROR [E0381]
+}
+
+fn main() { test(); }
diff --git a/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs b/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs
index d30b1de5cd0..a00fda60abb 100644
--- a/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs
+++ b/tests/ui/borrowck/borrowck-use-in-index-lvalue.rs
@@ -1,3 +1,5 @@
+//@ run-rustfix
+#[allow(unused_mut)]
 fn test() {
     let w: &mut [isize];
     w[5] = 0; //~ ERROR [E0381]
diff --git a/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr b/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr
index 18e808f10d0..6ec4390ae8d 100644
--- a/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr
+++ b/tests/ui/borrowck/borrowck-use-in-index-lvalue.stderr
@@ -1,5 +1,5 @@
 error[E0381]: used binding `w` isn't initialized
-  --> $DIR/borrowck-use-in-index-lvalue.rs:3:5
+  --> $DIR/borrowck-use-in-index-lvalue.rs:5:5
    |
 LL |     let w: &mut [isize];
    |         - binding declared here but left uninitialized
@@ -8,11 +8,11 @@ LL |     w[5] = 0;
    |
 help: consider assigning a value
    |
-LL |     let w: &mut [isize] = todo!();
+LL |     let w: &mut [isize] = &mut [];
    |                         +++++++++
 
 error[E0381]: used binding `w` isn't initialized
-  --> $DIR/borrowck-use-in-index-lvalue.rs:6:5
+  --> $DIR/borrowck-use-in-index-lvalue.rs:8:5
    |
 LL |     let mut w: &mut [isize];
    |         ----- binding declared here but left uninitialized
@@ -21,7 +21,7 @@ LL |     w[5] = 0;
    |
 help: consider assigning a value
    |
-LL |     let mut w: &mut [isize] = todo!();
+LL |     let mut w: &mut [isize] = &mut [];
    |                             +++++++++
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.fixed b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.fixed
new file mode 100644
index 00000000000..f6ea5f0b6b8
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.fixed
@@ -0,0 +1,12 @@
+// Variation on `borrowck-use-uninitialized-in-cast` in which we do a
+// trait cast from an uninitialized source. Issue #20791.
+//@ run-rustfix
+#![allow(unused_variables, dead_code)]
+
+trait Foo { fn dummy(&self) { } }
+impl Foo for i32 { }
+
+fn main() {
+    let x: &i32 = &42;
+    let y = x as *const dyn Foo; //~ ERROR [E0381]
+}
diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs
index 3ce72161814..a384fdbf950 100644
--- a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs
+++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.rs
@@ -1,5 +1,7 @@
 // Variation on `borrowck-use-uninitialized-in-cast` in which we do a
 // trait cast from an uninitialized source. Issue #20791.
+//@ run-rustfix
+#![allow(unused_variables, dead_code)]
 
 trait Foo { fn dummy(&self) { } }
 impl Foo for i32 { }
diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr
index dcbaa75333e..ef04979f1cd 100644
--- a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr
+++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr
@@ -1,5 +1,5 @@
 error[E0381]: used binding `x` isn't initialized
-  --> $DIR/borrowck-use-uninitialized-in-cast-trait.rs:9:13
+  --> $DIR/borrowck-use-uninitialized-in-cast-trait.rs:11:13
    |
 LL |     let x: &i32;
    |         - binding declared here but left uninitialized
@@ -8,8 +8,8 @@ LL |     let y = x as *const dyn Foo;
    |
 help: consider assigning a value
    |
-LL |     let x: &i32 = todo!();
-   |                 +++++++++
+LL |     let x: &i32 = &42;
+   |                 +++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.fixed b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.fixed
new file mode 100644
index 00000000000..9c72015d747
--- /dev/null
+++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.fixed
@@ -0,0 +1,10 @@
+// Check that we detect unused values that are cast to other things.
+// The problem was specified to casting to `*`, as creating unsafe
+// pointers was not being fully checked. Issue #20791.
+//@ run-rustfix
+#![allow(unused_variables)]
+
+fn main() {
+    let x: &i32 = &42;
+    let y = x as *const i32; //~ ERROR [E0381]
+}
diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs
index a355a546dc6..290deb0f257 100644
--- a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs
+++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.rs
@@ -1,6 +1,8 @@
 // Check that we detect unused values that are cast to other things.
 // The problem was specified to casting to `*`, as creating unsafe
 // pointers was not being fully checked. Issue #20791.
+//@ run-rustfix
+#![allow(unused_variables)]
 
 fn main() {
     let x: &i32;
diff --git a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr
index 7ccf6a4c3fc..22a3b721179 100644
--- a/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr
+++ b/tests/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr
@@ -1,5 +1,5 @@
 error[E0381]: used binding `x` isn't initialized
-  --> $DIR/borrowck-use-uninitialized-in-cast.rs:7:13
+  --> $DIR/borrowck-use-uninitialized-in-cast.rs:9:13
    |
 LL |     let x: &i32;
    |         - binding declared here but left uninitialized
@@ -8,8 +8,8 @@ LL |     let y = x as *const i32;
    |
 help: consider assigning a value
    |
-LL |     let x: &i32 = todo!();
-   |                 +++++++++
+LL |     let x: &i32 = &42;
+   |                 +++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/issue-103250.stderr b/tests/ui/borrowck/issue-103250.stderr
index b7ece5d971d..104bded5b0b 100644
--- a/tests/ui/borrowck/issue-103250.stderr
+++ b/tests/ui/borrowck/issue-103250.stderr
@@ -9,8 +9,8 @@ LL |         Err(last_error)
    |
 help: consider assigning a value
    |
-LL |         let mut last_error: Box<dyn std::error::Error> = todo!();
-   |                                                        +++++++++
+LL |         let mut last_error: Box<dyn std::error::Error> = Box::new(value);
+   |                                                        +++++++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/issue-24267-flow-exit.stderr b/tests/ui/borrowck/issue-24267-flow-exit.stderr
index 58d1c8c0f73..216f8d49b1b 100644
--- a/tests/ui/borrowck/issue-24267-flow-exit.stderr
+++ b/tests/ui/borrowck/issue-24267-flow-exit.stderr
@@ -10,8 +10,8 @@ LL |     println!("{}", x);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let x: i32 = 0;
-   |                +++
+LL |     let x: i32 = 42;
+   |                ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/issue-24267-flow-exit.rs:18:20
@@ -25,8 +25,8 @@ LL |     println!("{}", x);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let x: i32 = 0;
-   |                +++
+LL |     let x: i32 = 42;
+   |                ++++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr b/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr
index e19f37538c1..8705b8450fc 100644
--- a/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr
+++ b/tests/ui/borrowck/issue-62107-match-arm-scopes.stderr
@@ -9,8 +9,8 @@ LL |         ref u if true => {}
    |
 help: consider assigning a value
    |
-LL |     let e: i32 = 0;
-   |                +++
+LL |     let e: i32 = 42;
+   |                ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/suggest-assign-rvalue.stderr b/tests/ui/borrowck/suggest-assign-rvalue.stderr
index 92acba640d7..4305539f1b6 100644
--- a/tests/ui/borrowck/suggest-assign-rvalue.stderr
+++ b/tests/ui/borrowck/suggest-assign-rvalue.stderr
@@ -8,8 +8,8 @@ LL |     apple(chaenomeles);
    |
 help: consider assigning a value
    |
-LL |     let chaenomeles = 0;
-   |                     +++
+LL |     let chaenomeles = 42;
+   |                     ++++
 
 error[E0381]: used binding `my_float` isn't initialized
   --> $DIR/suggest-assign-rvalue.rs:23:30
@@ -22,8 +22,8 @@ LL |     println!("my_float: {}", my_float);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let my_float: f32 = 0.0;
-   |                       +++++
+LL |     let my_float: f32 = 3.14159;
+   |                       +++++++++
 
 error[E0381]: used binding `demo` isn't initialized
   --> $DIR/suggest-assign-rvalue.rs:26:28
@@ -50,8 +50,8 @@ LL |     println!("demo_no: {:?}", demo_no);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let demo_no: DemoNoDef = todo!();
-   |                            +++++++++
+LL |     let demo_no: DemoNoDef = value;
+   |                            +++++++
 
 error[E0381]: used binding `arr` isn't initialized
   --> $DIR/suggest-assign-rvalue.rs:34:27
@@ -64,7 +64,7 @@ LL |     println!("arr: {:?}", arr);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let arr: [i32; 5] = todo!();
+LL |     let arr: [i32; 5] = [42; 5];
    |                       +++++++++
 
 error[E0381]: used binding `foo` isn't initialized
@@ -106,8 +106,8 @@ LL |     println!("my_int: {}", *my_int);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let my_int: &i32 = todo!();
-   |                      +++++++++
+LL |     let my_int: &i32 = &42;
+   |                      +++++
 
 error[E0381]: used binding `hello` isn't initialized
   --> $DIR/suggest-assign-rvalue.rs:49:27
@@ -120,8 +120,8 @@ LL |     println!("hello: {}", hello);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let hello: &str = todo!();
-   |                     +++++++++
+LL |     let hello: &str = "";
+   |                     ++++
 
 error[E0381]: used binding `never` isn't initialized
   --> $DIR/suggest-assign-rvalue.rs:53:27
diff --git a/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr b/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
index 8a32f0d99e7..f8ed792e3c6 100644
--- a/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
+++ b/tests/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
@@ -79,8 +79,8 @@ LL |     let c1 = || match x { };
    |
 help: consider assigning a value
    |
-LL |     let x: u8 = 0;
-   |               +++
+LL |     let x: u8 = 42;
+   |               ++++
 
 error: aborting due to 8 previous errors
 
diff --git a/tests/ui/const-generics/const-generic-default-wont-borrowck.fixed b/tests/ui/const-generics/const-generic-default-wont-borrowck.fixed
new file mode 100644
index 00000000000..da48c62df21
--- /dev/null
+++ b/tests/ui/const-generics/const-generic-default-wont-borrowck.fixed
@@ -0,0 +1,6 @@
+//@ run-rustfix
+pub struct X<const N: usize = {
+    let s: &'static str = ""; s.len() //~ ERROR E0381
+}>;
+
+fn main() {}
diff --git a/tests/ui/const-generics/const-generic-default-wont-borrowck.rs b/tests/ui/const-generics/const-generic-default-wont-borrowck.rs
index e64adacac9f..0d7d87100b7 100644
--- a/tests/ui/const-generics/const-generic-default-wont-borrowck.rs
+++ b/tests/ui/const-generics/const-generic-default-wont-borrowck.rs
@@ -1,4 +1,5 @@
-struct X<const N: usize = {
+//@ run-rustfix
+pub struct X<const N: usize = {
     let s: &'static str; s.len() //~ ERROR E0381
 }>;
 
diff --git a/tests/ui/const-generics/const-generic-default-wont-borrowck.stderr b/tests/ui/const-generics/const-generic-default-wont-borrowck.stderr
index 4cea35f1c8e..83e7f88eda7 100644
--- a/tests/ui/const-generics/const-generic-default-wont-borrowck.stderr
+++ b/tests/ui/const-generics/const-generic-default-wont-borrowck.stderr
@@ -1,5 +1,5 @@
 error[E0381]: used binding `s` isn't initialized
-  --> $DIR/const-generic-default-wont-borrowck.rs:2:26
+  --> $DIR/const-generic-default-wont-borrowck.rs:3:26
    |
 LL |     let s: &'static str; s.len()
    |         -                ^ `*s` used here but it isn't initialized
@@ -8,8 +8,8 @@ LL |     let s: &'static str; s.len()
    |
 help: consider assigning a value
    |
-LL |     let s: &'static str = todo!(); s.len()
-   |                         +++++++++
+LL |     let s: &'static str = ""; s.len()
+   |                         ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/issue-78655.stderr b/tests/ui/consts/issue-78655.stderr
index 5a38d023d6f..ccaed03b4c1 100644
--- a/tests/ui/consts/issue-78655.stderr
+++ b/tests/ui/consts/issue-78655.stderr
@@ -8,8 +8,8 @@ LL |     &x
    |
 help: consider assigning a value
    |
-LL |     let x = 0;
-   |           +++
+LL |     let x = 42;
+   |           ++++
 
 error: could not evaluate constant pattern
   --> $DIR/issue-78655.rs:7:9
diff --git a/tests/ui/drop/repeat-drop-2.stderr b/tests/ui/drop/repeat-drop-2.stderr
index 009a2057212..cea7baf6976 100644
--- a/tests/ui/drop/repeat-drop-2.stderr
+++ b/tests/ui/drop/repeat-drop-2.stderr
@@ -32,8 +32,8 @@ LL |     let _ = [x; 0];
    |
 help: consider assigning a value
    |
-LL |     let x: u8 = 0;
-   |               +++
+LL |     let x: u8 = 42;
+   |               ++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/issues/issue-21596.rs b/tests/ui/issues/issue-21596.rs
deleted file mode 100644
index 79f6c91d9ac..00000000000
--- a/tests/ui/issues/issue-21596.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-fn main() {
-    let x = 8u8;
-    let z: *const u8 = &x;
-    println!("{}", z.to_string());  //~ ERROR E0599
-}
diff --git a/tests/ui/issues/issue-21596.stderr b/tests/ui/issues/issue-21596.stderr
deleted file mode 100644
index 8a7fca5f436..00000000000
--- a/tests/ui/issues/issue-21596.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0599]: `*const u8` doesn't implement `std::fmt::Display`
-  --> $DIR/issue-21596.rs:4:22
-   |
-LL |     println!("{}", z.to_string());
-   |                      ^^^^^^^^^ `*const u8` cannot be formatted with the default formatter
-   |
-   = note: try using `<*const T>::as_ref()` to get a reference to the type behind the pointer: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref
-   = note: using `<*const T>::as_ref()` on a pointer which is unaligned or points to invalid or uninitialized memory is undefined behavior
-   = note: the following trait bounds were not satisfied:
-           `*const u8: std::fmt::Display`
-           which is required by `*const u8: ToString`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/issues/issue-27042.stderr b/tests/ui/issues/issue-27042.stderr
index 01532de999e..ba39399e46e 100644
--- a/tests/ui/issues/issue-27042.stderr
+++ b/tests/ui/issues/issue-27042.stderr
@@ -19,7 +19,7 @@ LL |         loop { break };
    |         |
    |         this loop is expected to be of type `i32`
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |         loop { break 42 };
    |                      ++
diff --git a/tests/ui/loops/loop-break-value.rs b/tests/ui/loops/loop-break-value.rs
index c35200520cb..d509fc16570 100644
--- a/tests/ui/loops/loop-break-value.rs
+++ b/tests/ui/loops/loop-break-value.rs
@@ -23,6 +23,10 @@ fn main() {
         };
     };
 
+    let _: Option<String> = loop {
+        break; //~ ERROR mismatched types
+    };
+
     'while_loop: while true { //~ WARN denote infinite loops with
         break;
         break (); //~ ERROR `break` with value from a `while` loop
diff --git a/tests/ui/loops/loop-break-value.stderr b/tests/ui/loops/loop-break-value.stderr
index a691960f962..0093182422e 100644
--- a/tests/ui/loops/loop-break-value.stderr
+++ b/tests/ui/loops/loop-break-value.stderr
@@ -1,5 +1,5 @@
 warning: label name `'a` shadows a label name that is already in scope
-  --> $DIR/loop-break-value.rs:136:17
+  --> $DIR/loop-break-value.rs:140:17
    |
 LL |     'a: loop {
    |     -- first declared here
@@ -8,7 +8,7 @@ LL |         let _ = 'a: loop {
    |                 ^^ label `'a` already in scope
 
 warning: label name `'a` shadows a label name that is already in scope
-  --> $DIR/loop-break-value.rs:148:17
+  --> $DIR/loop-break-value.rs:152:17
    |
 LL |     'a: loop {
    |     -- first declared here
@@ -17,7 +17,7 @@ LL |         let _ = 'a: loop {
    |                 ^^ label `'a` already in scope
 
 error[E0425]: cannot find value `LOOP` in this scope
-  --> $DIR/loop-break-value.rs:95:15
+  --> $DIR/loop-break-value.rs:99:15
    |
 LL |     'LOOP: for _ in 0 .. 9 {
    |     ----- a label with a similar name exists
@@ -28,7 +28,7 @@ LL |         break LOOP;
    |               help: use the similarly named label: `'LOOP`
 
 warning: denote infinite loops with `loop { ... }`
-  --> $DIR/loop-break-value.rs:26:5
+  --> $DIR/loop-break-value.rs:30:5
    |
 LL |     'while_loop: while true {
    |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use `loop`
@@ -36,7 +36,7 @@ LL |     'while_loop: while true {
    = note: `#[warn(while_true)]` on by default
 
 error[E0571]: `break` with value from a `while` loop
-  --> $DIR/loop-break-value.rs:28:9
+  --> $DIR/loop-break-value.rs:32:9
    |
 LL |     'while_loop: while true {
    |     ----------------------- you can't `break` with a value in a `while` loop
@@ -54,7 +54,7 @@ LL |         break 'while_loop;
    |               ~~~~~~~~~~~
 
 error[E0571]: `break` with value from a `while` loop
-  --> $DIR/loop-break-value.rs:30:13
+  --> $DIR/loop-break-value.rs:34:13
    |
 LL |     'while_loop: while true {
    |     ----------------------- you can't `break` with a value in a `while` loop
@@ -68,7 +68,7 @@ LL |             break 'while_loop;
    |             ~~~~~~~~~~~~~~~~~
 
 error[E0571]: `break` with value from a `while` loop
-  --> $DIR/loop-break-value.rs:38:12
+  --> $DIR/loop-break-value.rs:42:12
    |
 LL |     while let Some(_) = Some(()) {
    |     ---------------------------- you can't `break` with a value in a `while` loop
@@ -81,7 +81,7 @@ LL |         if break {
    |            ~~~~~
 
 error[E0571]: `break` with value from a `while` loop
-  --> $DIR/loop-break-value.rs:43:9
+  --> $DIR/loop-break-value.rs:47:9
    |
 LL |     while let Some(_) = Some(()) {
    |     ---------------------------- you can't `break` with a value in a `while` loop
@@ -94,7 +94,7 @@ LL |         break;
    |         ~~~~~
 
 error[E0571]: `break` with value from a `while` loop
-  --> $DIR/loop-break-value.rs:49:13
+  --> $DIR/loop-break-value.rs:53:13
    |
 LL |     'while_let_loop: while let Some(_) = Some(()) {
    |     --------------------------------------------- you can't `break` with a value in a `while` loop
@@ -108,7 +108,7 @@ LL |             break 'while_let_loop;
    |             ~~~~~~~~~~~~~~~~~~~~~
 
 error[E0571]: `break` with value from a `for` loop
-  --> $DIR/loop-break-value.rs:56:9
+  --> $DIR/loop-break-value.rs:60:9
    |
 LL |     for _ in &[1,2,3] {
    |     ----------------- you can't `break` with a value in a `for` loop
@@ -121,7 +121,7 @@ LL |         break;
    |         ~~~~~
 
 error[E0571]: `break` with value from a `for` loop
-  --> $DIR/loop-break-value.rs:57:9
+  --> $DIR/loop-break-value.rs:61:9
    |
 LL |     for _ in &[1,2,3] {
    |     ----------------- you can't `break` with a value in a `for` loop
@@ -135,7 +135,7 @@ LL |         break;
    |         ~~~~~
 
 error[E0571]: `break` with value from a `for` loop
-  --> $DIR/loop-break-value.rs:64:13
+  --> $DIR/loop-break-value.rs:68:13
    |
 LL |     'for_loop: for _ in &[1,2,3] {
    |     ---------------------------- you can't `break` with a value in a `for` loop
@@ -191,7 +191,24 @@ LL |             break 'outer_loop "nope";
    |                               ^^^^^^ expected `i32`, found `&str`
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:73:26
+  --> $DIR/loop-break-value.rs:27:9
+   |
+LL |     let _: Option<String> = loop {
+   |         -                   ---- this loop is expected to be of type `Option<String>`
+   |         |
+   |         expected because of this assignment
+LL |         break;
+   |         ^^^^^ expected `Option<String>`, found `()`
+   |
+   = note:   expected enum `Option<String>`
+           found unit type `()`
+help: give the `break` a value of the expected type
+   |
+LL |         break None;
+   |               ++++
+
+error[E0308]: mismatched types
+  --> $DIR/loop-break-value.rs:77:26
    |
 LL |                 break;
    |                 ----- expected because of this `break`
@@ -199,7 +216,7 @@ LL |                 break 'c 123;
    |                          ^^^ expected `()`, found integer
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:80:15
+  --> $DIR/loop-break-value.rs:84:15
    |
 LL |         break (break, break);
    |               ^-----^^-----^
@@ -212,7 +229,7 @@ LL |         break (break, break);
                   found tuple `(!, !)`
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:85:15
+  --> $DIR/loop-break-value.rs:89:15
    |
 LL |         break;
    |         ----- expected because of this `break`
@@ -220,20 +237,20 @@ LL |         break 2;
    |               ^ expected `()`, found integer
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:90:9
+  --> $DIR/loop-break-value.rs:94:9
    |
 LL |         break 2;
    |         ------- expected because of this `break`
 LL |         break;
    |         ^^^^^ expected integer, found `()`
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |         break value;
    |               +++++
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:108:9
+  --> $DIR/loop-break-value.rs:112:9
    |
 LL |                     break 'a 1;
    |                     ---------- expected because of this `break`
@@ -241,13 +258,13 @@ LL |                     break 'a 1;
 LL |         break;
    |         ^^^^^ expected integer, found `()`
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |         break value;
    |               +++++
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:120:9
+  --> $DIR/loop-break-value.rs:124:9
    |
 LL |                     break 'a 1;
    |                     ---------- expected because of this `break`
@@ -255,13 +272,13 @@ LL |                     break 'a 1;
 LL |         break 'a;
    |         ^^^^^^^^ expected integer, found `()`
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |         break 'a value;
    |                  +++++
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:131:15
+  --> $DIR/loop-break-value.rs:135:15
    |
 LL |         break;
    |         ----- expected because of this `break`
@@ -270,7 +287,7 @@ LL |         break 2;
    |               ^ expected `()`, found integer
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:140:17
+  --> $DIR/loop-break-value.rs:144:17
    |
 LL |             break 2;
    |             ------- expected because of this `break`
@@ -278,13 +295,13 @@ LL |             loop {
 LL |                 break 'a;
    |                 ^^^^^^^^ expected integer, found `()`
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |                 break 'a value;
    |                          +++++
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:143:15
+  --> $DIR/loop-break-value.rs:147:15
    |
 LL |         break;
    |         ----- expected because of this `break`
@@ -293,7 +310,7 @@ LL |         break 2;
    |               ^ expected `()`, found integer
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:152:17
+  --> $DIR/loop-break-value.rs:156:17
    |
 LL |             break 'a 2;
    |             ---------- expected because of this `break`
@@ -301,13 +318,13 @@ LL |             loop {
 LL |                 break 'a;
    |                 ^^^^^^^^ expected integer, found `()`
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |                 break 'a value;
    |                          +++++
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:155:15
+  --> $DIR/loop-break-value.rs:159:15
    |
 LL |         break;
    |         ----- expected because of this `break`
@@ -316,7 +333,7 @@ LL |         break 2;
    |               ^ expected `()`, found integer
 
 error[E0308]: mismatched types
-  --> $DIR/loop-break-value.rs:159:15
+  --> $DIR/loop-break-value.rs:163:15
    |
 LL | fn main() {
    |          - expected `()` because of this return type
@@ -326,7 +343,7 @@ LL |     loop { // point at the return type
 LL |         break 2;
    |               ^ expected `()`, found integer
 
-error: aborting due to 25 previous errors; 3 warnings emitted
+error: aborting due to 26 previous errors; 3 warnings emitted
 
 Some errors have detailed explanations: E0308, E0425, E0571.
 For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/loops/loop-labeled-break-value.stderr b/tests/ui/loops/loop-labeled-break-value.stderr
index 694d6c306f6..3be62316e34 100644
--- a/tests/ui/loops/loop-labeled-break-value.stderr
+++ b/tests/ui/loops/loop-labeled-break-value.stderr
@@ -7,7 +7,7 @@ LL |         let _: i32 = loop { break };
    |             |        this loop is expected to be of type `i32`
    |             expected because of this assignment
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |         let _: i32 = loop { break 42 };
    |                                   ++
@@ -21,7 +21,7 @@ LL |         let _: i32 = 'inner: loop { break 'inner };
    |             |                this loop is expected to be of type `i32`
    |             expected because of this assignment
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |         let _: i32 = 'inner: loop { break 'inner 42 };
    |                                                  ++
@@ -35,7 +35,7 @@ LL |         let _: i32 = 'inner2: loop { loop { break 'inner2 } };
    |             |                 this loop is expected to be of type `i32`
    |             expected because of this assignment
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |         let _: i32 = 'inner2: loop { loop { break 'inner2 42 } };
    |                                                           ++
diff --git a/tests/ui/loops/loop-proper-liveness.stderr b/tests/ui/loops/loop-proper-liveness.stderr
index bcd6eb353e5..cd4c064bcd1 100644
--- a/tests/ui/loops/loop-proper-liveness.stderr
+++ b/tests/ui/loops/loop-proper-liveness.stderr
@@ -10,8 +10,8 @@ LL |     println!("{:?}", x);
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let x: i32 = 0;
-   |                +++
+LL |     let x: i32 = 42;
+   |                ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/loops/loop-properly-diverging-2.stderr b/tests/ui/loops/loop-properly-diverging-2.stderr
index c9f27a6a672..ba615f9ae4f 100644
--- a/tests/ui/loops/loop-properly-diverging-2.stderr
+++ b/tests/ui/loops/loop-properly-diverging-2.stderr
@@ -7,7 +7,7 @@ LL |   let x: i32 = loop { break };
    |       |        this loop is expected to be of type `i32`
    |       expected because of this assignment
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |   let x: i32 = loop { break 42 };
    |                             ++
diff --git a/tests/ui/methods/suggest-convert-ptr-to-ref.rs b/tests/ui/methods/suggest-convert-ptr-to-ref.rs
new file mode 100644
index 00000000000..ccce3c65470
--- /dev/null
+++ b/tests/ui/methods/suggest-convert-ptr-to-ref.rs
@@ -0,0 +1,17 @@
+fn main() {
+    let mut x = 8u8;
+    let z: *const u8 = &x;
+    // issue #21596
+    println!("{}", z.to_string()); //~ ERROR E0599
+
+    let t: *mut u8 = &mut x;
+    println!("{}", t.to_string()); //~ ERROR E0599
+    t.make_ascii_lowercase(); //~ ERROR E0599
+
+    // suggest `as_mut` simply because the name is similar
+    let _ = t.as_mut_ref(); //~ ERROR E0599
+    let _ = t.as_ref_mut(); //~ ERROR E0599
+
+    // no ptr-to-ref suggestion
+    z.make_ascii_lowercase(); //~ ERROR E0599
+}
diff --git a/tests/ui/methods/suggest-convert-ptr-to-ref.stderr b/tests/ui/methods/suggest-convert-ptr-to-ref.stderr
new file mode 100644
index 00000000000..69b20d57be8
--- /dev/null
+++ b/tests/ui/methods/suggest-convert-ptr-to-ref.stderr
@@ -0,0 +1,70 @@
+error[E0599]: `*const u8` doesn't implement `std::fmt::Display`
+  --> $DIR/suggest-convert-ptr-to-ref.rs:5:22
+   |
+LL |     println!("{}", z.to_string());
+   |                      ^^^^^^^^^ `*const u8` cannot be formatted with the default formatter
+   |
+note: the method `to_string` exists on the type `&u8`
+  --> $SRC_DIR/alloc/src/string.rs:LL:COL
+   = note: you might want to use the unsafe method `<*const T>::as_ref` to get an optional reference to the value behind the pointer
+   = note: read the documentation for `<*const T>::as_ref` and ensure you satisfy its safety preconditions before calling it to avoid undefined behavior: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref
+   = note: the following trait bounds were not satisfied:
+           `*const u8: std::fmt::Display`
+           which is required by `*const u8: ToString`
+
+error[E0599]: `*mut u8` doesn't implement `std::fmt::Display`
+  --> $DIR/suggest-convert-ptr-to-ref.rs:8:22
+   |
+LL |     println!("{}", t.to_string());
+   |                      ^^^^^^^^^ `*mut u8` cannot be formatted with the default formatter
+   |
+note: the method `to_string` exists on the type `&&mut u8`
+  --> $SRC_DIR/alloc/src/string.rs:LL:COL
+   = note: you might want to use the unsafe method `<*mut T>::as_ref` to get an optional reference to the value behind the pointer
+   = note: read the documentation for `<*mut T>::as_ref` and ensure you satisfy its safety preconditions before calling it to avoid undefined behavior: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_ref-1
+   = note: the following trait bounds were not satisfied:
+           `*mut u8: std::fmt::Display`
+           which is required by `*mut u8: ToString`
+
+error[E0599]: no method named `make_ascii_lowercase` found for raw pointer `*mut u8` in the current scope
+  --> $DIR/suggest-convert-ptr-to-ref.rs:9:7
+   |
+LL |     t.make_ascii_lowercase();
+   |       ^^^^^^^^^^^^^^^^^^^^ method not found in `*mut u8`
+   |
+note: the method `make_ascii_lowercase` exists on the type `&mut u8`
+  --> $SRC_DIR/core/src/num/mod.rs:LL:COL
+   = note: you might want to use the unsafe method `<*mut T>::as_mut` to get an optional reference to the value behind the pointer
+   = note: read the documentation for `<*mut T>::as_mut` and ensure you satisfy its safety preconditions before calling it to avoid undefined behavior: https://doc.rust-lang.org/std/primitive.pointer.html#method.as_mut
+
+error[E0599]: no method named `as_mut_ref` found for raw pointer `*mut u8` in the current scope
+  --> $DIR/suggest-convert-ptr-to-ref.rs:12:15
+   |
+LL |     let _ = t.as_mut_ref();
+   |               ^^^^^^^^^^
+   |
+help: there is a method `as_mut` with a similar name
+   |
+LL |     let _ = t.as_mut();
+   |               ~~~~~~
+
+error[E0599]: no method named `as_ref_mut` found for raw pointer `*mut u8` in the current scope
+  --> $DIR/suggest-convert-ptr-to-ref.rs:13:15
+   |
+LL |     let _ = t.as_ref_mut();
+   |               ^^^^^^^^^^
+   |
+help: there is a method `as_mut` with a similar name
+   |
+LL |     let _ = t.as_mut();
+   |               ~~~~~~
+
+error[E0599]: no method named `make_ascii_lowercase` found for raw pointer `*const u8` in the current scope
+  --> $DIR/suggest-convert-ptr-to-ref.rs:16:7
+   |
+LL |     z.make_ascii_lowercase();
+   |       ^^^^^^^^^^^^^^^^^^^^ method not found in `*const u8`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/moves/issue-72649-uninit-in-loop.stderr b/tests/ui/moves/issue-72649-uninit-in-loop.stderr
index 7e119fe8cda..49a5a188cde 100644
--- a/tests/ui/moves/issue-72649-uninit-in-loop.stderr
+++ b/tests/ui/moves/issue-72649-uninit-in-loop.stderr
@@ -56,8 +56,8 @@ LL |         let _used = value;
    |
 help: consider assigning a value
    |
-LL |         let value: NonCopy = todo!();
-   |                            +++++++++
+LL |         let value: NonCopy = value;
+   |                            +++++++
 
 error[E0381]: used binding `value` isn't initialized
   --> $DIR/issue-72649-uninit-in-loop.rs:69:21
@@ -70,8 +70,8 @@ LL |         let _used = value;
    |
 help: consider assigning a value
    |
-LL |     let mut value: NonCopy = todo!();
-   |                            +++++++++
+LL |     let mut value: NonCopy = value;
+   |                            +++++++
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/moves/move-into-dead-array-1.stderr b/tests/ui/moves/move-into-dead-array-1.stderr
index 83779fb16ed..d9b719730d6 100644
--- a/tests/ui/moves/move-into-dead-array-1.stderr
+++ b/tests/ui/moves/move-into-dead-array-1.stderr
@@ -8,8 +8,8 @@ LL |     a[i] = d();
    |
 help: consider assigning a value
    |
-LL |     let mut a: [D; 4] = todo!();
-   |                       +++++++++
+LL |     let mut a: [D; 4] = [value; 4];
+   |                       ++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/moves/move-of-addr-of-mut.stderr b/tests/ui/moves/move-of-addr-of-mut.stderr
index 706b52d3402..46f7d39a61a 100644
--- a/tests/ui/moves/move-of-addr-of-mut.stderr
+++ b/tests/ui/moves/move-of-addr-of-mut.stderr
@@ -9,8 +9,8 @@ LL |     std::ptr::addr_of_mut!(x);
    = note: this error originates in the macro `std::ptr::addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider assigning a value
    |
-LL |     let mut x: S = todo!();
-   |                  +++++++++
+LL |     let mut x: S = value;
+   |                  +++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/never_type/issue-52443.stderr b/tests/ui/never_type/issue-52443.stderr
index bab47064f6c..02cb9cb22a3 100644
--- a/tests/ui/never_type/issue-52443.stderr
+++ b/tests/ui/never_type/issue-52443.stderr
@@ -36,7 +36,7 @@ error[E0308]: mismatched types
 LL |     [(); loop { break }];
    |                 ^^^^^ expected `usize`, found `()`
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |     [(); loop { break 42 }];
    |                       ++
diff --git a/tests/ui/nll/match-cfg-fake-edges.stderr b/tests/ui/nll/match-cfg-fake-edges.stderr
index d692ded36fa..066e77b17fc 100644
--- a/tests/ui/nll/match-cfg-fake-edges.stderr
+++ b/tests/ui/nll/match-cfg-fake-edges.stderr
@@ -126,8 +126,8 @@ LL |         _ if { x; false } => 2,
    |
 help: consider assigning a value
    |
-LL |     let x = 0;
-   |           +++
+LL |     let x = 42;
+   |           ++++
 
 error[E0381]: used binding `x` isn't initialized
   --> $DIR/match-cfg-fake-edges.rs:86:31
@@ -142,8 +142,8 @@ LL |         _ if let Some(()) = { x; None } => 2,
    |
 help: consider assigning a value
    |
-LL |     let x = 0;
-   |           +++
+LL |     let x = 42;
+   |           ++++
 
 error[E0382]: use of moved value: `x`
   --> $DIR/match-cfg-fake-edges.rs:99:22
diff --git a/tests/ui/nll/match-on-borrowed.stderr b/tests/ui/nll/match-on-borrowed.stderr
index 9273484565a..4e0b048fb4b 100644
--- a/tests/ui/nll/match-on-borrowed.stderr
+++ b/tests/ui/nll/match-on-borrowed.stderr
@@ -43,8 +43,8 @@ LL |     match n {}
    |
 help: consider assigning a value
    |
-LL |     let n: Never = todo!();
-   |                  +++++++++
+LL |     let n: Never = value;
+   |                  +++++++
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/type/type-error-break-tail.stderr b/tests/ui/type/type-error-break-tail.stderr
index 5ef522fee2a..81f8f52428d 100644
--- a/tests/ui/type/type-error-break-tail.stderr
+++ b/tests/ui/type/type-error-break-tail.stderr
@@ -8,7 +8,7 @@ LL |     loop {
 LL |         if false { break; }
    |                    ^^^^^ expected `i32`, found `()`
    |
-help: give it a value of the expected type
+help: give the `break` a value of the expected type
    |
 LL |         if false { break 42; }
    |                          ++
diff --git a/tests/ui/uninhabited/privately-uninhabited-mir-call.fixed b/tests/ui/uninhabited/privately-uninhabited-mir-call.fixed
new file mode 100644
index 00000000000..76f4251daef
--- /dev/null
+++ b/tests/ui/uninhabited/privately-uninhabited-mir-call.fixed
@@ -0,0 +1,31 @@
+// Verifies that MIR building for a call expression respects
+// privacy when checking if a call return type is uninhabited.
+//@ run-rustfix
+#![allow(unreachable_code, unused_variables)]
+
+pub mod widget {
+    enum Unimplemented {}
+    pub struct Widget(Unimplemented);
+
+    impl Widget {
+        pub fn new() -> Widget {
+            todo!();
+        }
+    }
+
+    pub fn f() {
+        let x: &mut u32;
+        Widget::new();
+        // Ok. Widget type returned from new is known to be uninhabited
+        // and the following code is considered unreachable.
+        *x = 1;
+    }
+}
+
+fn main() {
+    let y: &mut u32 = &mut 42;
+    widget::Widget::new();
+    // Error. Widget type is not known to be uninhabited here,
+    // so the following code is considered reachable.
+    *y = 2; //~ ERROR E0381
+}
diff --git a/tests/ui/uninhabited/privately-uninhabited-mir-call.rs b/tests/ui/uninhabited/privately-uninhabited-mir-call.rs
index 2764bb563d3..1eec57ae046 100644
--- a/tests/ui/uninhabited/privately-uninhabited-mir-call.rs
+++ b/tests/ui/uninhabited/privately-uninhabited-mir-call.rs
@@ -1,5 +1,7 @@
 // Verifies that MIR building for a call expression respects
 // privacy when checking if a call return type is uninhabited.
+//@ run-rustfix
+#![allow(unreachable_code, unused_variables)]
 
 pub mod widget {
     enum Unimplemented {}
diff --git a/tests/ui/uninhabited/privately-uninhabited-mir-call.stderr b/tests/ui/uninhabited/privately-uninhabited-mir-call.stderr
index 5f2f02c99fb..9d0771ad79e 100644
--- a/tests/ui/uninhabited/privately-uninhabited-mir-call.stderr
+++ b/tests/ui/uninhabited/privately-uninhabited-mir-call.stderr
@@ -1,5 +1,5 @@
 error[E0381]: used binding `y` isn't initialized
-  --> $DIR/privately-uninhabited-mir-call.rs:28:5
+  --> $DIR/privately-uninhabited-mir-call.rs:30:5
    |
 LL |     let y: &mut u32;
    |         - binding declared here but left uninitialized
@@ -9,7 +9,7 @@ LL |     *y = 2;
    |
 help: consider assigning a value
    |
-LL |     let y: &mut u32 = todo!();
+LL |     let y: &mut u32 = &mut 42;
    |                     +++++++++
 
 error: aborting due to 1 previous error