about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-08-14 04:17:13 +0000
committerbors <bors@rust-lang.org>2024-08-14 04:17:13 +0000
commit9859bf27fd9892f48725c59b56aeee2be1d2fbad (patch)
tree1a8369bbb2d3e439f324e2095436c4ba3b1c3943
parente9c965df7b75ab5b1ae8f9a2680839ac1a1a3880 (diff)
parente01d6141a403af503c963794f8758ff49f057f84 (diff)
downloadrust-9859bf27fd9892f48725c59b56aeee2be1d2fbad.tar.gz
rust-9859bf27fd9892f48725c59b56aeee2be1d2fbad.zip
Auto merge of #129076 - matthiaskrgr:rollup-rg8mi2x, r=matthiaskrgr
Rollup of 6 pull requests

Successful merges:

 - #128410 (Migrate `remap-path-prefix-dwarf` `run-make` test to rmake)
 - #128759 (alloc: add ToString specialization for `&&str`)
 - #128873 (Add windows-targets crate to std's sysroot)
 - #129001 (chore(lib): Enhance documentation for core::fmt::Formatter's write_fm…)
 - #129061 (Use `is_lang_item` more)
 - #129062 (Remove a no-longer-true assert)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs10
-rw-r--r--compiler/rustc_lint/src/for_loops_over_fallibles.rs7
-rw-r--r--compiler/rustc_lint/src/traits.rs2
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs8
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs4
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs10
-rw-r--r--compiler/rustc_monomorphize/src/partitioning.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs31
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs3
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs4
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs2
-rw-r--r--library/Cargo.lock7
-rw-r--r--library/Cargo.toml1
-rw-r--r--library/alloc/src/string.rs54
-rw-r--r--library/core/src/fmt/mod.rs5
-rw-r--r--library/std/Cargo.toml5
-rw-r--r--library/std/src/sys/pal/windows/alloc.rs2
-rw-r--r--library/std/src/sys/pal/windows/c.rs2
-rw-r--r--library/std/src/sys/pal/windows/c/windows_sys.rs1
-rw-r--r--library/windows_targets/Cargo.toml10
-rw-r--r--library/windows_targets/src/lib.rs (renamed from library/std/src/sys/pal/windows/c/windows_targets.rs)4
-rw-r--r--src/tools/generate-windows-sys/src/main.rs1
-rw-r--r--src/tools/run-make-support/src/external_deps/llvm.rs30
-rw-r--r--src/tools/run-make-support/src/lib.rs5
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt1
-rw-r--r--src/tools/tidy/src/pal.rs1
-rw-r--r--tests/codegen/issues/str-to-string-128690.rs36
-rw-r--r--tests/run-make/remap-path-prefix-dwarf/Makefile112
-rw-r--r--tests/run-make/remap-path-prefix-dwarf/rmake.rs202
-rw-r--r--tests/ui/cast/ptr-to-trait-obj-different-args.stderr3
-rw-r--r--tests/ui/coercion/coerce-expect-unsized-ascribed.stderr4
-rw-r--r--tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr44
-rw-r--r--tests/ui/pattern/usefulness/empty-types.never_pats.stderr86
-rw-r--r--tests/ui/pattern/usefulness/empty-types.normal.stderr86
-rw-r--r--tests/ui/pattern/usefulness/empty-types.rs11
38 files changed, 543 insertions, 261 deletions
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 89df464cca0..cd357e4a7ad 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -160,15 +160,11 @@ pub(super) fn check_fn<'a, 'tcx>(
     fcx.demand_suptype(span, ret_ty, actual_return_ty);
 
     // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
-    if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
-        && panic_impl_did == fn_def_id.to_def_id()
-    {
-        check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig);
+    if tcx.is_lang_item(fn_def_id.to_def_id(), LangItem::PanicImpl) {
+        check_panic_info_fn(tcx, fn_def_id, fn_sig);
     }
 
-    if let Some(lang_start_defid) = tcx.lang_items().start_fn()
-        && lang_start_defid == fn_def_id.to_def_id()
-    {
+    if tcx.is_lang_item(fn_def_id.to_def_id(), LangItem::Start) {
         check_lang_start_fn(tcx, fn_sig, fn_def_id);
     }
 
diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
index 6cb5263ac54..2793d48dc51 100644
--- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -1,5 +1,5 @@
 use hir::{Expr, Pat};
-use rustc_hir as hir;
+use rustc_hir::{self as hir, LangItem};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::ty;
@@ -126,7 +126,10 @@ fn extract_iterator_next_call<'tcx>(
 ) -> Option<&'tcx Expr<'tcx>> {
     // This won't work for `Iterator::next(iter)`, is this an issue?
     if let hir::ExprKind::MethodCall(_, recv, _, _) = expr.kind
-        && cx.typeck_results().type_dependent_def_id(expr.hir_id) == cx.tcx.lang_items().next_fn()
+        && cx
+            .typeck_results()
+            .type_dependent_def_id(expr.hir_id)
+            .is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::IteratorNext))
     {
         Some(recv)
     } else {
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index fea96b5366e..a0fe4b5af74 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -114,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
         let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return };
         for (bound, modifier) in &bounds[..] {
             let def_id = bound.trait_ref.trait_def_id();
-            if cx.tcx.lang_items().drop_trait() == def_id
+            if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop))
                 && *modifier != hir::TraitBoundModifier::Maybe
             {
                 let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return };
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 5acc0b7ac7f..c14dadc68c9 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -6,10 +6,9 @@ use std::ops::ControlFlow;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{into_diag_arg_using_display, Applicability, Diag, DiagArgValue, IntoDiagArg};
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{PredicateOrigin, WherePredicate};
+use rustc_hir::{self as hir, LangItem, PredicateOrigin, WherePredicate};
 use rustc_span::{BytePos, Span};
 use rustc_type_ir::TyKind::*;
 
@@ -290,8 +289,9 @@ pub fn suggest_constraining_type_params<'a>(
         let Some(param) = param else { return false };
 
         {
-            let mut sized_constraints =
-                constraints.extract_if(|(_, def_id)| *def_id == tcx.lang_items().sized_trait());
+            let mut sized_constraints = constraints.extract_if(|(_, def_id)| {
+                def_id.is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Sized))
+            });
             if let Some((_, def_id)) = sized_constraints.next() {
                 applicability = Applicability::MaybeIncorrect;
 
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 0496c571f5e..6f19739de45 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -838,7 +838,7 @@ impl<'tcx> Instance<'tcx> {
             return None;
         };
 
-        if tcx.lang_items().get(coroutine_callable_item) == Some(trait_item_id) {
+        if tcx.is_lang_item(trait_item_id, coroutine_callable_item) {
             let ty::Coroutine(_, id_args) = *tcx.type_of(coroutine_def_id).skip_binder().kind()
             else {
                 bug!()
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 2dd0caf4f87..56ddf146636 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1145,7 +1145,9 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                         let term = if let Some(ty) = term.skip_binder().as_type()
                             && let ty::Alias(ty::Projection, proj) = ty.kind()
                             && let Some(assoc) = tcx.opt_associated_item(proj.def_id)
-                            && assoc.trait_container(tcx) == tcx.lang_items().coroutine_trait()
+                            && assoc
+                                .trait_container(tcx)
+                                .is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Coroutine))
                             && assoc.name == rustc_span::sym::Return
                         {
                             if let ty::Coroutine(_, args) = args.type_at(0).kind() {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 7ffbe38a55e..0a277fea49c 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1916,7 +1916,7 @@ impl<'tcx> Ty<'tcx> {
 
     pub fn is_c_void(self, tcx: TyCtxt<'_>) -> bool {
         match self.kind() {
-            ty::Adt(adt, _) => tcx.lang_items().get(LangItem::CVoid) == Some(adt.did()),
+            ty::Adt(adt, _) => tcx.is_lang_item(adt.did(), LangItem::CVoid),
             _ => false,
         }
     }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 07bf222fcca..85b9dacb129 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -702,10 +702,12 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             && adt.is_enum()
             && let Constructor::Variant(variant_index) = witness_1.ctor()
         {
-            let variant = adt.variant(*variant_index);
-            let inhabited = variant.inhabited_predicate(self.tcx, *adt).instantiate(self.tcx, args);
-            assert!(inhabited.apply(self.tcx, cx.param_env, cx.module));
-            !inhabited.apply_ignore_module(self.tcx, cx.param_env)
+            let variant_inhabited = adt
+                .variant(*variant_index)
+                .inhabited_predicate(self.tcx, *adt)
+                .instantiate(self.tcx, args);
+            variant_inhabited.apply(self.tcx, cx.param_env, cx.module)
+                && !variant_inhabited.apply_ignore_module(self.tcx, cx.param_env)
         } else {
             false
         };
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index 65a3d8d1742..f96329a3403 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -648,7 +648,9 @@ fn characteristic_def_id_of_mono_item<'tcx>(
 
             if let Some(impl_def_id) = tcx.impl_of_method(def_id) {
                 if tcx.sess.opts.incremental.is_some()
-                    && tcx.trait_id_of_impl(impl_def_id) == tcx.lang_items().drop_trait()
+                    && tcx
+                        .trait_id_of_impl(impl_def_id)
+                        .is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Drop))
                 {
                     // Put `Drop::drop` into the same cgu as `drop_in_place`
                     // since `drop_in_place` is the only thing that can
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index e77c738acce..05c79170902 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -4,6 +4,7 @@ use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
+use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::print::{FmtPrinter, Printer};
 use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
 use rustc_span::def_id::DefId;
@@ -313,11 +314,15 @@ impl<T> Trait<T> for X {
                     (ty::Dynamic(t, _, ty::DynKind::Dyn), _)
                         if let Some(def_id) = t.principal_def_id() =>
                     {
-                        let mut impl_def_ids = vec![];
+                        let mut has_matching_impl = false;
                         tcx.for_each_relevant_impl(def_id, values.found, |did| {
-                            impl_def_ids.push(did)
+                            if DeepRejectCtxt::new(tcx, TreatParams::ForLookup)
+                                .types_may_unify(values.found, tcx.type_of(did).skip_binder())
+                            {
+                                has_matching_impl = true;
+                            }
                         });
-                        if let [_] = &impl_def_ids[..] {
+                        if has_matching_impl {
                             let trait_name = tcx.item_name(def_id);
                             diag.help(format!(
                                 "`{}` implements `{trait_name}` so you could box the found value \
@@ -330,11 +335,15 @@ impl<T> Trait<T> for X {
                     (_, ty::Dynamic(t, _, ty::DynKind::Dyn))
                         if let Some(def_id) = t.principal_def_id() =>
                     {
-                        let mut impl_def_ids = vec![];
+                        let mut has_matching_impl = false;
                         tcx.for_each_relevant_impl(def_id, values.expected, |did| {
-                            impl_def_ids.push(did)
+                            if DeepRejectCtxt::new(tcx, TreatParams::ForLookup)
+                                .types_may_unify(values.expected, tcx.type_of(did).skip_binder())
+                            {
+                                has_matching_impl = true;
+                            }
                         });
-                        if let [_] = &impl_def_ids[..] {
+                        if has_matching_impl {
                             let trait_name = tcx.item_name(def_id);
                             diag.help(format!(
                                 "`{}` implements `{trait_name}` so you could change the expected \
@@ -346,11 +355,15 @@ impl<T> Trait<T> for X {
                     (ty::Dynamic(t, _, ty::DynKind::DynStar), _)
                         if let Some(def_id) = t.principal_def_id() =>
                     {
-                        let mut impl_def_ids = vec![];
+                        let mut has_matching_impl = false;
                         tcx.for_each_relevant_impl(def_id, values.found, |did| {
-                            impl_def_ids.push(did)
+                            if DeepRejectCtxt::new(tcx, TreatParams::ForLookup)
+                                .types_may_unify(values.found, tcx.type_of(did).skip_binder())
+                            {
+                                has_matching_impl = true;
+                            }
                         });
-                        if let [_] = &impl_def_ids[..] {
+                        if has_matching_impl {
                             let trait_name = tcx.item_name(def_id);
                             diag.help(format!(
                                 "`{}` implements `{trait_name}`, `#[feature(dyn_star)]` is likely \
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 99ae342b54c..326a0e4e35c 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -230,8 +230,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             post_message,
                         );
 
-                        let (err_msg, safe_transmute_explanation) = if Some(main_trait_ref.def_id())
-                            == self.tcx.lang_items().transmute_trait()
+                        let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_ref.def_id(), LangItem::TransmuteTrait)
                         {
                             // Recompute the safe transmute reason and use that for the error reporting
                             match self.get_safe_transmute_error_and_reason(
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 2c3adf73eee..d0f76f0d50e 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -2831,7 +2831,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                                     // Do not suggest relaxing if there is an explicit `Sized` obligation.
                                     && !bounds.iter()
                                         .filter_map(|bound| bound.trait_ref())
-                                        .any(|tr| tr.trait_def_id() == tcx.lang_items().sized_trait())
+                                        .any(|tr| tr.trait_def_id().is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Sized)))
                                 {
                                     let (span, separator) = if let [.., last] = bounds {
                                         (last.span().shrink_to_hi(), " +")
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
index 294c6bfc124..d6687c762c3 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
@@ -1,3 +1,4 @@
+use rustc_hir::LangItem;
 use rustc_infer::traits::Obligation;
 pub use rustc_middle::traits::query::type_op::ProvePredicate;
 use rustc_middle::traits::query::NoSolution;
@@ -20,8 +21,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
         // such cases.
         if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) =
             key.value.predicate.kind().skip_binder()
-            && let Some(sized_def_id) = tcx.lang_items().sized_trait()
-            && trait_ref.def_id() == sized_def_id
+            && tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized)
             && trait_ref.self_ty().is_trivially_sized(tcx)
         {
             return Some(());
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index d90c3bedc70..34c426f2aa6 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -621,7 +621,7 @@ fn fn_abi_new_uncached<'tcx>(
     let rust_abi = matches!(sig.abi, RustIntrinsic | Rust | RustCall);
 
     let is_drop_in_place =
-        fn_def_id.is_some() && fn_def_id == cx.tcx.lang_items().drop_in_place_fn();
+        fn_def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::DropInPlace));
 
     let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, &'tcx FnAbiError<'tcx>> {
         let span = tracing::debug_span!("arg_of");
diff --git a/library/Cargo.lock b/library/Cargo.lock
index b36399d880e..815f5bb1385 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -339,6 +339,7 @@ dependencies = [
  "std_detect",
  "unwind",
  "wasi",
+ "windows-targets 0.0.0",
 ]
 
 [[package]]
@@ -421,11 +422,15 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
 name = "windows-targets"
+version = "0.0.0"
+
+[[package]]
+name = "windows-targets"
 version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
diff --git a/library/Cargo.toml b/library/Cargo.toml
index c4513b4c127..d8ece6b0ebd 100644
--- a/library/Cargo.toml
+++ b/library/Cargo.toml
@@ -8,6 +8,7 @@ members = [
 exclude = [
   # stdarch has its own Cargo workspace
   "stdarch",
+  "windows_targets"
 ]
 
 [profile.release.package.compiler_builtins]
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 124230812df..e628be1546f 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -2643,14 +2643,54 @@ impl ToString for i8 {
     }
 }
 
-#[doc(hidden)]
+// Generic/generated code can sometimes have multiple, nested references
+// for strings, including `&&&str`s that would never be written
+// by hand. This macro generates twelve layers of nested `&`-impl
+// for primitive strings.
 #[cfg(not(no_global_oom_handling))]
-#[stable(feature = "str_to_string_specialization", since = "1.9.0")]
-impl ToString for str {
-    #[inline]
-    fn to_string(&self) -> String {
-        String::from(self)
-    }
+macro_rules! to_string_str_wrap_in_ref {
+    {x $($x:ident)*} => {
+        &to_string_str_wrap_in_ref! { $($x)* }
+    };
+    {} => { str };
+}
+#[cfg(not(no_global_oom_handling))]
+macro_rules! to_string_expr_wrap_in_deref {
+    {$self:expr ; x $($x:ident)*} => {
+        *(to_string_expr_wrap_in_deref! { $self ; $($x)* })
+    };
+    {$self:expr ;} => { $self };
+}
+#[cfg(not(no_global_oom_handling))]
+macro_rules! to_string_str {
+    {$($($x:ident)*),+} => {
+        $(
+            #[doc(hidden)]
+            #[stable(feature = "str_to_string_specialization", since = "1.9.0")]
+            impl ToString for to_string_str_wrap_in_ref!($($x)*) {
+                #[inline]
+                fn to_string(&self) -> String {
+                    String::from(to_string_expr_wrap_in_deref!(self ; $($x)*))
+                }
+            }
+        )+
+    };
+}
+
+#[cfg(not(no_global_oom_handling))]
+to_string_str! {
+    x x x x x x x x x x x x,
+    x x x x x x x x x x x,
+    x x x x x x x x x x,
+    x x x x x x x x x,
+    x x x x x x x x,
+    x x x x x x x,
+    x x x x x x,
+    x x x x x,
+    x x x x,
+    x x x,
+    x x,
+    x,
 }
 
 #[doc(hidden)]
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 485ad4aee19..45c2b6a6a0f 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -1626,6 +1626,11 @@ impl<'a> Formatter<'a> {
         self.buf.write_str(data)
     }
 
+    /// Glue for usage of the [`write!`] macro with implementors of this trait.
+    ///
+    /// This method should generally not be invoked manually, but rather through
+    /// the [`write!`] macro itself.
+    ///
     /// Writes some formatted information into this instance.
     ///
     /// # Examples
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 2ce284c85e2..7f23681ee45 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -57,6 +57,9 @@ object = { version = "0.36.0", default-features = false, optional = true, featur
     'archive',
 ] }
 
+[target.'cfg(windows)'.dependencies.windows-targets]
+path = "../windows_targets"
+
 [dev-dependencies]
 rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
 rand_xorshift = "0.3.0"
@@ -116,7 +119,7 @@ std_detect_env_override = ["std_detect/std_detect_env_override"]
 
 # Enable using raw-dylib for Windows imports.
 # This will eventually be the default.
-windows_raw_dylib = []
+windows_raw_dylib = ["windows-targets/windows_raw_dylib"]
 
 [package.metadata.fortanix-sgx]
 # Maximum possible number of threads when testing
diff --git a/library/std/src/sys/pal/windows/alloc.rs b/library/std/src/sys/pal/windows/alloc.rs
index 92b68b26032..2205885687d 100644
--- a/library/std/src/sys/pal/windows/alloc.rs
+++ b/library/std/src/sys/pal/windows/alloc.rs
@@ -4,7 +4,7 @@ use crate::alloc::{GlobalAlloc, Layout, System};
 use crate::ffi::c_void;
 use crate::ptr;
 use crate::sync::atomic::{AtomicPtr, Ordering};
-use crate::sys::c::{self, windows_targets};
+use crate::sys::c;
 use crate::sys::common::alloc::{realloc_fallback, MIN_ALIGN};
 
 #[cfg(test)]
diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
index 08b75186aef..2f5d75dc4bc 100644
--- a/library/std/src/sys/pal/windows/c.rs
+++ b/library/std/src/sys/pal/windows/c.rs
@@ -8,8 +8,6 @@
 use core::ffi::{c_uint, c_ulong, c_ushort, c_void, CStr};
 use core::{mem, ptr};
 
-pub(super) mod windows_targets;
-
 mod windows_sys;
 pub use windows_sys::*;
 
diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs
index 9f22f548195..529c96a0e1e 100644
--- a/library/std/src/sys/pal/windows/c/windows_sys.rs
+++ b/library/std/src/sys/pal/windows/c/windows_sys.rs
@@ -3317,4 +3317,3 @@ pub struct WSADATA {
 #[cfg(target_arch = "arm")]
 pub enum CONTEXT {}
 // ignore-tidy-filelength
-use super::windows_targets;
diff --git a/library/windows_targets/Cargo.toml b/library/windows_targets/Cargo.toml
new file mode 100644
index 00000000000..94d7c821064
--- /dev/null
+++ b/library/windows_targets/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "windows-targets"
+description = "A drop-in replacement for the real windows-targets crate for use in std only."
+version = "0.0.0"
+edition = "2021"
+
+[features]
+# Enable using raw-dylib for Windows imports.
+# This will eventually be the default.
+windows_raw_dylib = []
diff --git a/library/std/src/sys/pal/windows/c/windows_targets.rs b/library/windows_targets/src/lib.rs
index 252bceb7094..1965b6cf4ce 100644
--- a/library/std/src/sys/pal/windows/c/windows_targets.rs
+++ b/library/windows_targets/src/lib.rs
@@ -2,6 +2,10 @@
 //!
 //! This is a simple wrapper around an `extern` block with a `#[link]` attribute.
 //! It's very roughly equivalent to the windows-targets crate.
+#![no_std]
+#![no_core]
+#![feature(decl_macro)]
+#![feature(no_core)]
 
 #[cfg(feature = "windows_raw_dylib")]
 pub macro link {
diff --git a/src/tools/generate-windows-sys/src/main.rs b/src/tools/generate-windows-sys/src/main.rs
index fe1b1bd5ceb..6dbf29d957f 100644
--- a/src/tools/generate-windows-sys/src/main.rs
+++ b/src/tools/generate-windows-sys/src/main.rs
@@ -35,7 +35,6 @@ fn main() -> Result<(), Box<dyn Error>> {
     let mut f = std::fs::File::options().append(true).open("windows_sys.rs")?;
     f.write_all(ARM32_SHIM.as_bytes())?;
     writeln!(&mut f, "// ignore-tidy-filelength")?;
-    writeln!(&mut f, "use super::windows_targets;")?;
 
     Ok(())
 }
diff --git a/src/tools/run-make-support/src/external_deps/llvm.rs b/src/tools/run-make-support/src/external_deps/llvm.rs
index dc651fdd820..7af79443aff 100644
--- a/src/tools/run-make-support/src/external_deps/llvm.rs
+++ b/src/tools/run-make-support/src/external_deps/llvm.rs
@@ -48,6 +48,12 @@ pub fn llvm_bcanalyzer() -> LlvmBcanalyzer {
     LlvmBcanalyzer::new()
 }
 
+/// Construct a new `llvm-dwarfdump` invocation. This assumes that `llvm-dwarfdump` is available
+/// at `$LLVM_BIN_DIR/llvm-dwarfdump`.
+pub fn llvm_dwarfdump() -> LlvmDwarfdump {
+    LlvmDwarfdump::new()
+}
+
 /// A `llvm-readobj` invocation builder.
 #[derive(Debug)]
 #[must_use]
@@ -97,6 +103,13 @@ pub struct LlvmBcanalyzer {
     cmd: Command,
 }
 
+/// A `llvm-dwarfdump` invocation builder.
+#[derive(Debug)]
+#[must_use]
+pub struct LlvmDwarfdump {
+    cmd: Command,
+}
+
 crate::macros::impl_common_helpers!(LlvmReadobj);
 crate::macros::impl_common_helpers!(LlvmProfdata);
 crate::macros::impl_common_helpers!(LlvmFilecheck);
@@ -104,6 +117,7 @@ crate::macros::impl_common_helpers!(LlvmObjdump);
 crate::macros::impl_common_helpers!(LlvmAr);
 crate::macros::impl_common_helpers!(LlvmNm);
 crate::macros::impl_common_helpers!(LlvmBcanalyzer);
+crate::macros::impl_common_helpers!(LlvmDwarfdump);
 
 /// Generate the path to the bin directory of LLVM.
 #[must_use]
@@ -317,3 +331,19 @@ impl LlvmBcanalyzer {
         self
     }
 }
+
+impl LlvmDwarfdump {
+    /// Construct a new `llvm-dwarfdump` invocation. This assumes that `llvm-dwarfdump` is available
+    /// at `$LLVM_BIN_DIR/llvm-dwarfdump`.
+    pub fn new() -> Self {
+        let llvm_dwarfdump = llvm_bin_dir().join("llvm-dwarfdump");
+        let cmd = Command::new(llvm_dwarfdump);
+        Self { cmd }
+    }
+
+    /// Provide an input file.
+    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+        self.cmd.arg(path.as_ref());
+        self
+    }
+}
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index a44dd00ad79..4d0c1b0930c 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -49,8 +49,9 @@ pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_nativ
 pub use clang::{clang, Clang};
 pub use htmldocck::htmldocck;
 pub use llvm::{
-    llvm_ar, llvm_bcanalyzer, llvm_filecheck, llvm_nm, llvm_objdump, llvm_profdata, llvm_readobj,
-    LlvmAr, LlvmBcanalyzer, LlvmFilecheck, LlvmNm, LlvmObjdump, LlvmProfdata, LlvmReadobj,
+    llvm_ar, llvm_bcanalyzer, llvm_dwarfdump, llvm_filecheck, llvm_nm, llvm_objdump, llvm_profdata,
+    llvm_readobj, LlvmAr, LlvmBcanalyzer, LlvmDwarfdump, LlvmFilecheck, LlvmNm, LlvmObjdump,
+    LlvmProfdata, LlvmReadobj,
 };
 pub use python::python_command;
 pub use rustc::{aux_build, bare_rustc, rustc, Rustc};
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 14f0a9cd23d..2d25de46f6e 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -16,7 +16,6 @@ run-make/macos-deployment-target/Makefile
 run-make/min-global-align/Makefile
 run-make/native-link-modifier-bundle/Makefile
 run-make/no-alloc-shim/Makefile
-run-make/remap-path-prefix-dwarf/Makefile
 run-make/reproducible-build/Makefile
 run-make/rlib-format-packed-bundled-libs/Makefile
 run-make/split-debuginfo/Makefile
diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs
index b7ddf47186d..c650fd0eec6 100644
--- a/src/tools/tidy/src/pal.rs
+++ b/src/tools/tidy/src/pal.rs
@@ -36,6 +36,7 @@ use crate::walk::{filter_dirs, walk};
 
 // Paths that may contain platform-specific code.
 const EXCEPTION_PATHS: &[&str] = &[
+    "library/windows_targets",
     "library/panic_abort",
     "library/panic_unwind",
     "library/unwind",
diff --git a/tests/codegen/issues/str-to-string-128690.rs b/tests/codegen/issues/str-to-string-128690.rs
new file mode 100644
index 00000000000..8b416306ba6
--- /dev/null
+++ b/tests/codegen/issues/str-to-string-128690.rs
@@ -0,0 +1,36 @@
+//@ compile-flags: -C opt-level=3 -Z merge-functions=disabled
+#![crate_type = "lib"]
+
+//! Make sure str::to_string is specialized not to use fmt machinery.
+
+// CHECK-LABEL: define {{(dso_local )?}}void @one_ref
+#[no_mangle]
+pub fn one_ref(input: &str) -> String {
+    // CHECK-NOT: {{(call|invoke).*}}fmt
+    input.to_string()
+}
+
+// CHECK-LABEL: define {{(dso_local )?}}void @two_ref
+#[no_mangle]
+pub fn two_ref(input: &&str) -> String {
+    // CHECK-NOT: {{(call|invoke).*}}fmt
+    input.to_string()
+}
+
+// CHECK-LABEL: define {{(dso_local )?}}void @thirteen_ref
+#[no_mangle]
+pub fn thirteen_ref(input: &&&&&&&&&&&&&str) -> String {
+    // CHECK-NOT: {{(call|invoke).*}}fmt
+    input.to_string()
+}
+
+// This is a known performance cliff because of the macro-generated
+// specialized impl. If this test suddenly starts failing,
+// consider removing the `to_string_str!` macro in `alloc/str/string.rs`.
+//
+// CHECK-LABEL: define {{(dso_local )?}}void @fourteen_ref
+#[no_mangle]
+pub fn fourteen_ref(input: &&&&&&&&&&&&&&str) -> String {
+    // CHECK: {{(call|invoke).*}}fmt
+    input.to_string()
+}
diff --git a/tests/run-make/remap-path-prefix-dwarf/Makefile b/tests/run-make/remap-path-prefix-dwarf/Makefile
deleted file mode 100644
index 8905a00ea28..00000000000
--- a/tests/run-make/remap-path-prefix-dwarf/Makefile
+++ /dev/null
@@ -1,112 +0,0 @@
-# This test makes sure that --remap-path-prefix has the expected effects on paths in debuginfo.
-# It tests several cases, each of them has a detailed description attached to it.
-
-# ignore-windows
-
-include ../tools.mk
-
-SRC_DIR := $(abspath .)
-SRC_DIR_PARENT := $(abspath ..)
-
-ifeq ($(UNAME),Darwin)
-  DEBUGINFOOPTS := -Csplit-debuginfo=off
-else
-  DEBUGINFOOPTS :=
-endif
-
-all: \
-  abs_input_outside_working_dir \
-  rel_input_remap_working_dir \
-  rel_input_remap_working_dir_scope \
-  rel_input_remap_working_dir_parent \
-  rel_input_remap_working_dir_child \
-  rel_input_remap_working_dir_diagnostics \
-  abs_input_inside_working_dir \
-  abs_input_inside_working_dir_scope \
-  abs_input_outside_working_dir
-
-# The compiler is called with an *ABSOLUTE PATH* as input, and that absolute path *is* within
-# the working directory of the compiler. We are remapping the path that contains `src`.
-abs_input_inside_working_dir:
-	# We explicitly switch to a directory that *is* a prefix of the directory our
-	# source code is contained in.
-	cd $(SRC_DIR) && $(RUSTC) $(SRC_DIR)/src/quux.rs -o "$(TMPDIR)/abs_input_inside_working_dir.rlib" -Cdebuginfo=2 --remap-path-prefix $(SRC_DIR)=REMAPPED
-	# We expect the path to the main source file to be remapped.
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump $(TMPDIR)/abs_input_inside_working_dir.rlib | $(CGREP) "REMAPPED/src/quux.rs"
-	# No weird duplication of remapped components (see #78479)
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump $(TMPDIR)/abs_input_inside_working_dir.rlib | $(CGREP) -v "REMAPPED/REMAPPED"
-
-# The compiler is called with an *ABSOLUTE PATH* as input, and that absolute path *is* within
-# the working directory of the compiler. We are remapping the path that contains `src`.
-abs_input_inside_working_dir_scope:
-	# We explicitly switch to a directory that *is* a prefix of the directory our
-	# source code is contained in.
-	cd $(SRC_DIR) && $(RUSTC) $(SRC_DIR)/src/quux.rs -o "$(TMPDIR)/abs_input_inside_working_dir_scope.rlib" -Cdebuginfo=2 --remap-path-prefix $(SRC_DIR)=REMAPPED -Zremap-path-scope=object $(DEBUGINFOOPTS)
-	# We expect the path to the main source file to be remapped.
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump $(TMPDIR)/abs_input_inside_working_dir_scope.rlib | $(CGREP) "REMAPPED/src/quux.rs"
-	# No weird duplication of remapped components (see #78479)
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump $(TMPDIR)/abs_input_inside_working_dir_scope.rlib | $(CGREP) -v "REMAPPED/REMAPPED"
-
-# The compiler is called with an *ABSOLUTE PATH* as input, and that absolute path is *not* within
-# the working directory of the compiler. We are remapping both the path that contains `src` and
-# the working directory to the same thing. This setup corresponds to a workaround that is needed
-# when trying to remap everything to something that looks like a local path.
-# Relative paths are interpreted as relative to the compiler's working directory (e.g. in
-# debuginfo). If we also remap the working directory, the compiler strip it from other paths so
-# that the final outcome is the desired one again.
-abs_input_outside_working_dir:
-	# We explicitly switch to a directory that is *not* a prefix of the directory our
-	# source code is contained in.
-	cd $(TMPDIR) && $(RUSTC) $(SRC_DIR)/src/quux.rs -o "$(TMPDIR)/abs_input_outside_working_dir.rlib" -Cdebuginfo=2 --remap-path-prefix $(SRC_DIR)=REMAPPED --remap-path-prefix $(TMPDIR)=REMAPPED
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump $(TMPDIR)/abs_input_outside_working_dir.rlib | $(CGREP) "REMAPPED/src/quux.rs"
-	# No weird duplication of remapped components (see #78479)
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump $(TMPDIR)/abs_input_outside_working_dir.rlib | $(CGREP) -v "REMAPPED/REMAPPED"
-
-# The compiler is called with a *RELATIVE PATH* as input. We are remapping the working directory of
-# the compiler, which naturally is an implicit prefix of our relative input path. Debuginfo will
-# expand the relative path to an absolute path and we expect the working directory to be remapped
-# in that expansion.
-rel_input_remap_working_dir:
-	cd $(SRC_DIR) && $(RUSTC) src/quux.rs -o "$(TMPDIR)/rel_input_remap_working_dir.rlib" -Cdebuginfo=2 --remap-path-prefix "$(SRC_DIR)=REMAPPED"
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir.rlib" | $(CGREP) "REMAPPED/src/quux.rs"
-	# No weird duplication of remapped components (see #78479)
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir.rlib" | $(CGREP) -v "REMAPPED/REMAPPED"
-
-# The compiler is called with a *RELATIVE PATH* as input. We are remapping the working directory of
-# the compiler, which naturally is an implicit prefix of our relative input path. Debuginfo will
-# expand the relative path to an absolute path and we expect the working directory to be remapped
-# in that expansion.
-rel_input_remap_working_dir_scope:
-	cd $(SRC_DIR) && $(RUSTC) src/quux.rs -o "$(TMPDIR)/rel_input_remap_working_dir_scope.rlib" -Cdebuginfo=2 --remap-path-prefix "$(SRC_DIR)=REMAPPED" -Zremap-path-scope=object $(DEBUGINFOOPTS)
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir_scope.rlib" | $(CGREP) "REMAPPED/src/quux.rs"
-	# No weird duplication of remapped components (see #78479)
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir_scope.rlib" | $(CGREP) -v "REMAPPED/REMAPPED"
-
-rel_input_remap_working_dir_diagnostics:
-	cd $(SRC_DIR) && $(RUSTC) src/quux.rs -o "$(TMPDIR)/rel_input_remap_working_dir_scope.rlib" -Cdebuginfo=2 --remap-path-prefix "$(SRC_DIR)=REMAPPED" -Zremap-path-scope=diagnostics $(DEBUGINFOOPTS)
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir_scope.rlib" | $(CGREP) -v "REMAPPED/src/quux.rs"
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir_scope.rlib" | $(CGREP) -v "REMAPPED/REMAPPED"
-
-# The compiler is called with a *RELATIVE PATH* as input. We are remapping a *SUB-DIRECTORY* of the
-# compiler's working directory. This test makes sure that that directory is remapped even though it
-# won't actually show up in this form in the compiler's SourceMap and instead is only constructed
-# on demand during debuginfo generation.
-rel_input_remap_working_dir_child:
-	cd $(SRC_DIR) && $(RUSTC) src/quux.rs -o "$(TMPDIR)/rel_input_remap_working_dir_child.rlib" -Cdebuginfo=2 --remap-path-prefix "$(SRC_DIR)/src=REMAPPED"
-	# We expect `src/quux.rs` to have been remapped to `REMAPPED/quux.rs`.
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir_child.rlib" | $(CGREP) "REMAPPED/quux.rs"
-	# We don't want to find the path that we just remapped anywhere in the DWARF
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir_child.rlib" | $(CGREP) -v "$(SRC_DIR)/src"
-	# No weird duplication of remapped components (see #78479)
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir_child.rlib" | $(CGREP) -v "REMAPPED/REMAPPED"
-
-# The compiler is called with a *RELATIVE PATH* as input. We are remapping a *PARENT DIRECTORY* of
-# the compiler's working directory.
-rel_input_remap_working_dir_parent:
-	cd $(SRC_DIR) && $(RUSTC) src/quux.rs -o "$(TMPDIR)/rel_input_remap_working_dir_parent.rlib" -Cdebuginfo=2 --remap-path-prefix "$(SRC_DIR_PARENT)=REMAPPED"
-	# We expect `src/quux.rs` to have been remapped to `REMAPPED/remap-path-prefix-dwarf/src/quux.rs`.
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir_parent.rlib" | $(CGREP) "REMAPPED/remap-path-prefix-dwarf/src/quux.rs"
-	# We don't want to find the path that we just remapped anywhere in the DWARF
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir_parent.rlib" | $(CGREP) -v "$(SRC_DIR_PARENT)"
-	# No weird duplication of remapped components (see #78479)
-	"$(LLVM_BIN_DIR)"/llvm-dwarfdump "$(TMPDIR)/rel_input_remap_working_dir_parent.rlib" | $(CGREP) -v "REMAPPED/REMAPPED"
diff --git a/tests/run-make/remap-path-prefix-dwarf/rmake.rs b/tests/run-make/remap-path-prefix-dwarf/rmake.rs
new file mode 100644
index 00000000000..ede1d615742
--- /dev/null
+++ b/tests/run-make/remap-path-prefix-dwarf/rmake.rs
@@ -0,0 +1,202 @@
+// This test makes sure that --remap-path-prefix has the expected effects on paths in debuginfo.
+// We explicitly switch to a directory that *is* a prefix of the directory our
+// source code is contained in.
+// It tests several cases, each of them has a detailed description attached to it.
+// See https://github.com/rust-lang/rust/pull/96867
+
+//@ ignore-windows
+// Reason: the remap path prefix is not printed in the dwarf dump.
+
+use run_make_support::{cwd, is_darwin, llvm_dwarfdump, rust_lib_name, rustc};
+
+fn main() {
+    // The compiler is called with an *ABSOLUTE PATH* as input, and that absolute path *is* within
+    // the working directory of the compiler. We are remapping the path that contains `src`.
+    check_dwarf(DwarfTest {
+        lib_name: "abs_input_inside_working_dir",
+        input_path: PathType::Absolute,
+        scope: None,
+        remap_path_prefix: PrefixType::Regular(format!("{}=REMAPPED", cwd().display())),
+        dwarf_test: DwarfDump::ContainsSrcPath,
+    });
+    check_dwarf(DwarfTest {
+        lib_name: "abs_input_inside_working_dir_scope",
+        input_path: PathType::Absolute,
+        scope: Some(ScopeType::Object),
+        remap_path_prefix: PrefixType::Regular(format!("{}=REMAPPED", cwd().display())),
+        dwarf_test: DwarfDump::ContainsSrcPath,
+    });
+    // The compiler is called with an *ABSOLUTE PATH* as input, and that absolute path is *not*
+    // within the working directory of the compiler. We are remapping both the path that contains
+    // `src` and the working directory to the same thing. This setup corresponds to a workaround
+    // that is needed when trying to remap everything to something that looks like a local
+    // path. Relative paths are interpreted as relative to the compiler's working directory (e.g.
+    // in debuginfo). If we also remap the working directory, the compiler strip it from other
+    // paths so that the final outcome is the desired one again.
+    check_dwarf(DwarfTest {
+        lib_name: "abs_input_outside_working_dir",
+        input_path: PathType::Absolute,
+        scope: None,
+        remap_path_prefix: PrefixType::Dual((
+            format!("{}=REMAPPED", cwd().display()),
+            "rmake_out=REMAPPED".to_owned(),
+        )),
+        dwarf_test: DwarfDump::ContainsSrcPath,
+    });
+    // The compiler is called with a *RELATIVE PATH* as input. We are remapping the working
+    // directory of the compiler, which naturally is an implicit prefix of our relative input path.
+    // Debuginfo will expand the relative path to an absolute path and we expect the working
+    // directory to be remapped in that expansion.
+    check_dwarf(DwarfTest {
+        lib_name: "rel_input_remap_working_dir",
+        input_path: PathType::Relative,
+        scope: None,
+        remap_path_prefix: PrefixType::Regular(format!("{}=REMAPPED", cwd().display())),
+        dwarf_test: DwarfDump::ContainsSrcPath,
+    });
+    check_dwarf(DwarfTest {
+        lib_name: "rel_input_remap_working_dir_scope",
+        input_path: PathType::Relative,
+        scope: Some(ScopeType::Object),
+        remap_path_prefix: PrefixType::Regular(format!("{}=REMAPPED", cwd().display())),
+        dwarf_test: DwarfDump::ContainsSrcPath,
+    });
+    check_dwarf(DwarfTest {
+        lib_name: "rel_input_remap_working_dir_scope",
+        input_path: PathType::Relative,
+        scope: Some(ScopeType::Diagnostics),
+        remap_path_prefix: PrefixType::Regular(format!("{}=REMAPPED", cwd().display())),
+        dwarf_test: DwarfDump::AvoidSrcPath,
+    });
+    // The compiler is called with a *RELATIVE PATH* as input. We are remapping a *SUB-DIRECTORY*
+    // of the compiler's working directory. This test makes sure that that directory is remapped
+    // even though it won't actually show up in this form in the compiler's SourceMap and instead
+    // is only constructed on demand during debuginfo generation.
+    check_dwarf(DwarfTest {
+        lib_name: "rel_input_remap_working_dir_child",
+        input_path: PathType::Relative,
+        scope: None,
+        remap_path_prefix: PrefixType::Regular(format!("{}=REMAPPED", cwd().join("src").display())),
+        dwarf_test: DwarfDump::ChildTest,
+    });
+    // The compiler is called with a *RELATIVE PATH* as input. We are remapping a
+    // *PARENT DIRECTORY* of the compiler's working directory.
+    check_dwarf(DwarfTest {
+        lib_name: "rel_input_remap_working_dir_parent",
+        input_path: PathType::Relative,
+        scope: None,
+        remap_path_prefix: PrefixType::Regular(format!(
+            "{}=REMAPPED",
+            cwd().parent().unwrap().display()
+        )),
+        dwarf_test: DwarfDump::ParentTest,
+    });
+}
+
+#[track_caller]
+fn check_dwarf(test: DwarfTest) {
+    let mut rustc = rustc();
+    match test.input_path {
+        PathType::Absolute => rustc.input(cwd().join("src/quux.rs")),
+        PathType::Relative => rustc.input("src/quux.rs"),
+    };
+    rustc.output(rust_lib_name(test.lib_name));
+    rustc.arg("-Cdebuginfo=2");
+    if let Some(scope) = test.scope {
+        match scope {
+            ScopeType::Object => rustc.arg("-Zremap-path-scope=object"),
+            ScopeType::Diagnostics => rustc.arg("-Zremap-path-scope=diagnostics"),
+        };
+        if is_darwin() {
+            rustc.arg("-Csplit-debuginfo=off");
+        }
+    }
+    match test.remap_path_prefix {
+        PrefixType::Regular(prefix) => {
+            // We explicitly switch to a directory that *is* a prefix of the directory our
+            // source code is contained in.
+            rustc.arg("--remap-path-prefix");
+            rustc.arg(prefix);
+        }
+        PrefixType::Dual((prefix1, prefix2)) => {
+            // We explicitly switch to a directory that is *not* a prefix of the directory our
+            // source code is contained in.
+            rustc.arg("--remap-path-prefix");
+            rustc.arg(prefix1);
+            rustc.arg("--remap-path-prefix");
+            rustc.arg(prefix2);
+        }
+    }
+    rustc.run();
+    match test.dwarf_test {
+        DwarfDump::ContainsSrcPath => {
+            llvm_dwarfdump()
+                .input(rust_lib_name(test.lib_name))
+                .run()
+                // We expect the path to the main source file to be remapped.
+                .assert_stdout_contains("REMAPPED/src/quux.rs")
+                // No weird duplication of remapped components (see #78479)
+                .assert_stdout_not_contains("REMAPPED/REMAPPED");
+        }
+        DwarfDump::AvoidSrcPath => {
+            llvm_dwarfdump()
+                .input(rust_lib_name(test.lib_name))
+                .run()
+                .assert_stdout_not_contains("REMAPPED/src/quux.rs")
+                .assert_stdout_not_contains("REMAPPED/REMAPPED");
+        }
+        DwarfDump::ChildTest => {
+            llvm_dwarfdump()
+                .input(rust_lib_name(test.lib_name))
+                .run()
+                // We expect `src/quux.rs` to have been remapped to `REMAPPED/quux.rs`.
+                .assert_stdout_contains("REMAPPED/quux.rs")
+                // We don't want to find the path that we just remapped anywhere in the DWARF
+                .assert_stdout_not_contains(cwd().join("src").to_str().unwrap())
+                // No weird duplication of remapped components (see #78479)
+                .assert_stdout_not_contains("REMAPPED/REMAPPED");
+        }
+        DwarfDump::ParentTest => {
+            llvm_dwarfdump()
+                .input(rust_lib_name(test.lib_name))
+                .run()
+                // We expect `src/quux.rs` to have been remapped to
+                // `REMAPPED/remap-path-prefix-dwarf/src/quux.rs`.
+                .assert_stdout_contains("REMAPPED/rmake_out/src/quux.rs")
+                // We don't want to find the path that we just remapped anywhere in the DWARF
+                .assert_stdout_not_contains(cwd().parent().unwrap().to_str().unwrap())
+                // No weird duplication of remapped components (see #78479)
+                .assert_stdout_not_contains("REMAPPED/REMAPPED");
+        }
+    };
+}
+
+struct DwarfTest {
+    lib_name: &'static str,
+    input_path: PathType,
+    scope: Option<ScopeType>,
+    remap_path_prefix: PrefixType,
+    dwarf_test: DwarfDump,
+}
+
+enum PathType {
+    Absolute,
+    Relative,
+}
+
+enum ScopeType {
+    Object,
+    Diagnostics,
+}
+
+enum DwarfDump {
+    ContainsSrcPath,
+    AvoidSrcPath,
+    ChildTest,
+    ParentTest,
+}
+
+enum PrefixType {
+    Regular(String),
+    Dual((String, String)),
+}
diff --git a/tests/ui/cast/ptr-to-trait-obj-different-args.stderr b/tests/ui/cast/ptr-to-trait-obj-different-args.stderr
index b04289ae747..8e60ca42f0a 100644
--- a/tests/ui/cast/ptr-to-trait-obj-different-args.stderr
+++ b/tests/ui/cast/ptr-to-trait-obj-different-args.stderr
@@ -14,6 +14,7 @@ LL |     let y: *const dyn Trait<Y> = x as _;
    |
    = note: expected trait object `dyn Trait<X>`
               found trait object `dyn Trait<Y>`
+   = help: `dyn Trait<Y>` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
 
 error[E0308]: mismatched types
   --> $DIR/ptr-to-trait-obj-different-args.rs:27:34
@@ -25,6 +26,7 @@ LL |     let _: *const dyn Trait<T> = x as _;
    |
    = note: expected trait object `dyn Trait<X>`
               found trait object `dyn Trait<T>`
+   = help: `dyn Trait<T>` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
 
 error[E0308]: mismatched types
   --> $DIR/ptr-to-trait-obj-different-args.rs:28:34
@@ -37,6 +39,7 @@ LL |     let _: *const dyn Trait<X> = t as _;
    |
    = note: expected trait object `dyn Trait<T>`
               found trait object `dyn Trait<X>`
+   = help: `dyn Trait<X>` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
 
 error[E0308]: mismatched types
   --> $DIR/ptr-to-trait-obj-different-args.rs:36:5
diff --git a/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr b/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr
index 646044ae41a..0c220a13876 100644
--- a/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr
+++ b/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr
@@ -42,6 +42,7 @@ LL |     let _ = type_ascribe!(Box::new( if true { false } else { true }), Box<d
    |
    = note: expected struct `Box<dyn Debug>`
               found struct `Box<bool>`
+   = help: `bool` implements `Debug` so you could box the found value and coerce it to the trait object `Box<dyn Debug>`, you will have to change the expected type as well
 
 error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:16:27
@@ -51,6 +52,7 @@ LL |     let _ = type_ascribe!(Box::new( match true { true => 'a', false => 'b'
    |
    = note: expected struct `Box<dyn Debug>`
               found struct `Box<char>`
+   = help: `char` implements `Debug` so you could box the found value and coerce it to the trait object `Box<dyn Debug>`, you will have to change the expected type as well
 
 error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:18:27
@@ -96,6 +98,7 @@ LL |     let _ = type_ascribe!(&if true { false } else { true }, &dyn Debug);
    |
    = note: expected reference `&dyn Debug`
               found reference `&bool`
+   = help: `bool` implements `Debug` so you could box the found value and coerce it to the trait object `Box<dyn Debug>`, you will have to change the expected type as well
 
 error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:24:27
@@ -105,6 +108,7 @@ LL |     let _ = type_ascribe!(&match true { true => 'a', false => 'b' }, &dyn D
    |
    = note: expected reference `&dyn Debug`
               found reference `&char`
+   = help: `char` implements `Debug` so you could box the found value and coerce it to the trait object `Box<dyn Debug>`, you will have to change the expected type as well
 
 error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:26:27
diff --git a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr
index 17cb6fbd94b..f6f341d6f2f 100644
--- a/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr
+++ b/tests/ui/pattern/usefulness/empty-types.exhaustive_patterns.stderr
@@ -254,7 +254,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:279:9
+  --> $DIR/empty-types.rs:281:9
    |
 LL |         _ => {}
    |         ^
@@ -262,7 +262,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:282:9
+  --> $DIR/empty-types.rs:284:9
    |
 LL |         (_, _) => {}
    |         ^^^^^^
@@ -270,7 +270,7 @@ LL |         (_, _) => {}
    = note: this pattern matches no values because `(!, !)` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:285:9
+  --> $DIR/empty-types.rs:287:9
    |
 LL |         Ok(_) => {}
    |         ^^^^^
@@ -278,7 +278,7 @@ LL |         Ok(_) => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:286:9
+  --> $DIR/empty-types.rs:288:9
    |
 LL |         Err(_) => {}
    |         ^^^^^^
@@ -286,7 +286,7 @@ LL |         Err(_) => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty
-  --> $DIR/empty-types.rs:318:11
+  --> $DIR/empty-types.rs:327:11
    |
 LL |     match slice_never {}
    |           ^^^^^^^^^^^
@@ -300,7 +300,7 @@ LL +     }
    |
 
 error[E0004]: non-exhaustive patterns: `&[]` not covered
-  --> $DIR/empty-types.rs:329:11
+  --> $DIR/empty-types.rs:338:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ pattern `&[]` not covered
@@ -313,7 +313,7 @@ LL +         &[] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[]` not covered
-  --> $DIR/empty-types.rs:343:11
+  --> $DIR/empty-types.rs:352:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ pattern `&[]` not covered
@@ -327,7 +327,7 @@ LL +         &[] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: type `[!]` is non-empty
-  --> $DIR/empty-types.rs:350:11
+  --> $DIR/empty-types.rs:359:11
    |
 LL |     match *slice_never {}
    |           ^^^^^^^^^^^^
@@ -341,7 +341,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:359:9
+  --> $DIR/empty-types.rs:368:9
    |
 LL |         _ => {}
    |         ^
@@ -349,7 +349,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:362:9
+  --> $DIR/empty-types.rs:371:9
    |
 LL |         [_, _, _] => {}
    |         ^^^^^^^^^
@@ -357,7 +357,7 @@ LL |         [_, _, _] => {}
    = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:365:9
+  --> $DIR/empty-types.rs:374:9
    |
 LL |         [_, ..] => {}
    |         ^^^^^^^
@@ -365,7 +365,7 @@ LL |         [_, ..] => {}
    = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty
-  --> $DIR/empty-types.rs:379:11
+  --> $DIR/empty-types.rs:388:11
    |
 LL |     match array_0_never {}
    |           ^^^^^^^^^^^^^
@@ -379,7 +379,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:386:9
+  --> $DIR/empty-types.rs:395:9
    |
 LL |         [] => {}
    |         -- matches all the values already
@@ -387,7 +387,7 @@ LL |         _ => {}
    |         ^ unreachable pattern
 
 error[E0004]: non-exhaustive patterns: `[]` not covered
-  --> $DIR/empty-types.rs:388:11
+  --> $DIR/empty-types.rs:397:11
    |
 LL |     match array_0_never {
    |           ^^^^^^^^^^^^^ pattern `[]` not covered
@@ -401,7 +401,7 @@ LL +         [] => todo!()
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:407:9
+  --> $DIR/empty-types.rs:416:9
    |
 LL |         Some(_) => {}
    |         ^^^^^^^
@@ -409,7 +409,7 @@ LL |         Some(_) => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:412:9
+  --> $DIR/empty-types.rs:421:9
    |
 LL |         Some(_a) => {}
    |         ^^^^^^^^
@@ -417,7 +417,7 @@ LL |         Some(_a) => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:417:9
+  --> $DIR/empty-types.rs:426:9
    |
 LL |         None => {}
    |         ---- matches all the values already
@@ -426,7 +426,7 @@ LL |         _ => {}
    |         ^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:422:9
+  --> $DIR/empty-types.rs:431:9
    |
 LL |         None => {}
    |         ---- matches all the values already
@@ -435,7 +435,7 @@ LL |         _a => {}
    |         ^^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:594:9
+  --> $DIR/empty-types.rs:603:9
    |
 LL |         _ => {}
    |         ^
@@ -443,7 +443,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:597:9
+  --> $DIR/empty-types.rs:606:9
    |
 LL |         _x => {}
    |         ^^
@@ -451,7 +451,7 @@ LL |         _x => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:600:9
+  --> $DIR/empty-types.rs:609:9
    |
 LL |         _ if false => {}
    |         ^
@@ -459,7 +459,7 @@ LL |         _ if false => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:603:9
+  --> $DIR/empty-types.rs:612:9
    |
 LL |         _x if false => {}
    |         ^^
diff --git a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr
index 1ecb15f2cae..55a138c2d1c 100644
--- a/tests/ui/pattern/usefulness/empty-types.never_pats.stderr
+++ b/tests/ui/pattern/usefulness/empty-types.never_pats.stderr
@@ -296,7 +296,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:279:9
+  --> $DIR/empty-types.rs:281:9
    |
 LL |         _ => {}
    |         ^
@@ -304,7 +304,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:282:9
+  --> $DIR/empty-types.rs:284:9
    |
 LL |         (_, _) => {}
    |         ^^^^^^
@@ -312,7 +312,7 @@ LL |         (_, _) => {}
    = note: this pattern matches no values because `(!, !)` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:285:9
+  --> $DIR/empty-types.rs:287:9
    |
 LL |         Ok(_) => {}
    |         ^^^^^
@@ -320,15 +320,29 @@ LL |         Ok(_) => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:286:9
+  --> $DIR/empty-types.rs:288:9
    |
 LL |         Err(_) => {}
    |         ^^^^^^
    |
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
+error[E0005]: refutable pattern in local binding
+  --> $DIR/empty-types.rs:297:13
+   |
+LL |         let Ok(_) = *ptr_result_never_err;
+   |             ^^^^^ pattern `Err(!)` not covered
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+   = note: the matched value is of type `Result<u8, !>`
+help: you might want to use `if let` to ignore the variant that isn't matched
+   |
+LL |         if let Ok(_) = *ptr_result_never_err { todo!() };
+   |         ++                                   +++++++++++
+
 error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty
-  --> $DIR/empty-types.rs:307:11
+  --> $DIR/empty-types.rs:316:11
    |
 LL |     match *x {}
    |           ^^
@@ -342,7 +356,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty
-  --> $DIR/empty-types.rs:309:11
+  --> $DIR/empty-types.rs:318:11
    |
 LL |     match *x {}
    |           ^^
@@ -356,7 +370,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: `Ok(!)` and `Err(!)` not covered
-  --> $DIR/empty-types.rs:311:11
+  --> $DIR/empty-types.rs:320:11
    |
 LL |     match *x {}
    |           ^^ patterns `Ok(!)` and `Err(!)` not covered
@@ -378,7 +392,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty
-  --> $DIR/empty-types.rs:313:11
+  --> $DIR/empty-types.rs:322:11
    |
 LL |     match *x {}
    |           ^^
@@ -392,7 +406,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty
-  --> $DIR/empty-types.rs:318:11
+  --> $DIR/empty-types.rs:327:11
    |
 LL |     match slice_never {}
    |           ^^^^^^^^^^^
@@ -406,7 +420,7 @@ LL +     }
    |
 
 error[E0004]: non-exhaustive patterns: `&[!, ..]` not covered
-  --> $DIR/empty-types.rs:320:11
+  --> $DIR/empty-types.rs:329:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ pattern `&[!, ..]` not covered
@@ -420,7 +434,7 @@ LL +         &[!, ..]
    |
 
 error[E0004]: non-exhaustive patterns: `&[]`, `&[!]` and `&[!, !]` not covered
-  --> $DIR/empty-types.rs:329:11
+  --> $DIR/empty-types.rs:338:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ patterns `&[]`, `&[!]` and `&[!, !]` not covered
@@ -433,7 +447,7 @@ LL +         &[] | &[!] | &[!, !] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[!, ..]` not covered
-  --> $DIR/empty-types.rs:343:11
+  --> $DIR/empty-types.rs:352:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ patterns `&[]` and `&[!, ..]` not covered
@@ -447,7 +461,7 @@ LL +         &[] | &[!, ..] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: type `[!]` is non-empty
-  --> $DIR/empty-types.rs:350:11
+  --> $DIR/empty-types.rs:359:11
    |
 LL |     match *slice_never {}
    |           ^^^^^^^^^^^^
@@ -461,7 +475,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:359:9
+  --> $DIR/empty-types.rs:368:9
    |
 LL |         _ => {}
    |         ^
@@ -469,7 +483,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:362:9
+  --> $DIR/empty-types.rs:371:9
    |
 LL |         [_, _, _] => {}
    |         ^^^^^^^^^
@@ -477,7 +491,7 @@ LL |         [_, _, _] => {}
    = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:365:9
+  --> $DIR/empty-types.rs:374:9
    |
 LL |         [_, ..] => {}
    |         ^^^^^^^
@@ -485,7 +499,7 @@ LL |         [_, ..] => {}
    = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty
-  --> $DIR/empty-types.rs:379:11
+  --> $DIR/empty-types.rs:388:11
    |
 LL |     match array_0_never {}
    |           ^^^^^^^^^^^^^
@@ -499,7 +513,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:386:9
+  --> $DIR/empty-types.rs:395:9
    |
 LL |         [] => {}
    |         -- matches all the values already
@@ -507,7 +521,7 @@ LL |         _ => {}
    |         ^ unreachable pattern
 
 error[E0004]: non-exhaustive patterns: `[]` not covered
-  --> $DIR/empty-types.rs:388:11
+  --> $DIR/empty-types.rs:397:11
    |
 LL |     match array_0_never {
    |           ^^^^^^^^^^^^^ pattern `[]` not covered
@@ -521,7 +535,7 @@ LL +         [] => todo!()
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:407:9
+  --> $DIR/empty-types.rs:416:9
    |
 LL |         Some(_) => {}
    |         ^^^^^^^
@@ -529,7 +543,7 @@ LL |         Some(_) => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:412:9
+  --> $DIR/empty-types.rs:421:9
    |
 LL |         Some(_a) => {}
    |         ^^^^^^^^
@@ -537,7 +551,7 @@ LL |         Some(_a) => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:417:9
+  --> $DIR/empty-types.rs:426:9
    |
 LL |         None => {}
    |         ---- matches all the values already
@@ -546,7 +560,7 @@ LL |         _ => {}
    |         ^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:422:9
+  --> $DIR/empty-types.rs:431:9
    |
 LL |         None => {}
    |         ---- matches all the values already
@@ -555,7 +569,7 @@ LL |         _a => {}
    |         ^^ unreachable pattern
 
 error[E0004]: non-exhaustive patterns: `&Some(!)` not covered
-  --> $DIR/empty-types.rs:442:11
+  --> $DIR/empty-types.rs:451:11
    |
 LL |     match ref_opt_never {
    |           ^^^^^^^^^^^^^ pattern `&Some(!)` not covered
@@ -574,7 +588,7 @@ LL +         &Some(!)
    |
 
 error[E0004]: non-exhaustive patterns: `Some(!)` not covered
-  --> $DIR/empty-types.rs:483:11
+  --> $DIR/empty-types.rs:492:11
    |
 LL |     match *ref_opt_never {
    |           ^^^^^^^^^^^^^^ pattern `Some(!)` not covered
@@ -593,7 +607,7 @@ LL +         Some(!)
    |
 
 error[E0004]: non-exhaustive patterns: `Err(!)` not covered
-  --> $DIR/empty-types.rs:531:11
+  --> $DIR/empty-types.rs:540:11
    |
 LL |     match *ref_res_never {
    |           ^^^^^^^^^^^^^^ pattern `Err(!)` not covered
@@ -612,7 +626,7 @@ LL +         Err(!)
    |
 
 error[E0004]: non-exhaustive patterns: `Err(!)` not covered
-  --> $DIR/empty-types.rs:542:11
+  --> $DIR/empty-types.rs:551:11
    |
 LL |     match *ref_res_never {
    |           ^^^^^^^^^^^^^^ pattern `Err(!)` not covered
@@ -631,7 +645,7 @@ LL +         Err(!)
    |
 
 error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty
-  --> $DIR/empty-types.rs:561:11
+  --> $DIR/empty-types.rs:570:11
    |
 LL |     match *ref_tuple_half_never {}
    |           ^^^^^^^^^^^^^^^^^^^^^
@@ -645,7 +659,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:594:9
+  --> $DIR/empty-types.rs:603:9
    |
 LL |         _ => {}
    |         ^
@@ -653,7 +667,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:597:9
+  --> $DIR/empty-types.rs:606:9
    |
 LL |         _x => {}
    |         ^^
@@ -661,7 +675,7 @@ LL |         _x => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:600:9
+  --> $DIR/empty-types.rs:609:9
    |
 LL |         _ if false => {}
    |         ^
@@ -669,7 +683,7 @@ LL |         _ if false => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:603:9
+  --> $DIR/empty-types.rs:612:9
    |
 LL |         _x if false => {}
    |         ^^
@@ -677,7 +691,7 @@ LL |         _x if false => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: `&!` not covered
-  --> $DIR/empty-types.rs:628:11
+  --> $DIR/empty-types.rs:637:11
    |
 LL |     match ref_never {
    |           ^^^^^^^^^ pattern `&!` not covered
@@ -693,7 +707,7 @@ LL +         &!
    |
 
 error[E0004]: non-exhaustive patterns: `Ok(!)` not covered
-  --> $DIR/empty-types.rs:644:11
+  --> $DIR/empty-types.rs:653:11
    |
 LL |     match *ref_result_never {
    |           ^^^^^^^^^^^^^^^^^ pattern `Ok(!)` not covered
@@ -712,7 +726,7 @@ LL +         Ok(!)
    |
 
 error[E0004]: non-exhaustive patterns: `Some(!)` not covered
-  --> $DIR/empty-types.rs:664:11
+  --> $DIR/empty-types.rs:673:11
    |
 LL |     match *x {
    |           ^^ pattern `Some(!)` not covered
@@ -730,7 +744,7 @@ LL ~         None => {},
 LL +         Some(!)
    |
 
-error: aborting due to 64 previous errors; 1 warning emitted
+error: aborting due to 65 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0004, E0005.
 For more information about an error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/empty-types.normal.stderr b/tests/ui/pattern/usefulness/empty-types.normal.stderr
index c3421cd592e..83b3989ffde 100644
--- a/tests/ui/pattern/usefulness/empty-types.normal.stderr
+++ b/tests/ui/pattern/usefulness/empty-types.normal.stderr
@@ -287,7 +287,7 @@ LL |             _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:279:9
+  --> $DIR/empty-types.rs:281:9
    |
 LL |         _ => {}
    |         ^
@@ -295,7 +295,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:282:9
+  --> $DIR/empty-types.rs:284:9
    |
 LL |         (_, _) => {}
    |         ^^^^^^
@@ -303,7 +303,7 @@ LL |         (_, _) => {}
    = note: this pattern matches no values because `(!, !)` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:285:9
+  --> $DIR/empty-types.rs:287:9
    |
 LL |         Ok(_) => {}
    |         ^^^^^
@@ -311,15 +311,29 @@ LL |         Ok(_) => {}
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:286:9
+  --> $DIR/empty-types.rs:288:9
    |
 LL |         Err(_) => {}
    |         ^^^^^^
    |
    = note: this pattern matches no values because `Result<!, !>` is uninhabited
 
+error[E0005]: refutable pattern in local binding
+  --> $DIR/empty-types.rs:297:13
+   |
+LL |         let Ok(_) = *ptr_result_never_err;
+   |             ^^^^^ pattern `Err(_)` not covered
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+   = note: the matched value is of type `Result<u8, !>`
+help: you might want to use `if let` to ignore the variant that isn't matched
+   |
+LL |         if let Ok(_) = *ptr_result_never_err { todo!() };
+   |         ++                                   +++++++++++
+
 error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty
-  --> $DIR/empty-types.rs:307:11
+  --> $DIR/empty-types.rs:316:11
    |
 LL |     match *x {}
    |           ^^
@@ -333,7 +347,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `(!, !)` is non-empty
-  --> $DIR/empty-types.rs:309:11
+  --> $DIR/empty-types.rs:318:11
    |
 LL |     match *x {}
    |           ^^
@@ -347,7 +361,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: `Ok(_)` and `Err(_)` not covered
-  --> $DIR/empty-types.rs:311:11
+  --> $DIR/empty-types.rs:320:11
    |
 LL |     match *x {}
    |           ^^ patterns `Ok(_)` and `Err(_)` not covered
@@ -369,7 +383,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `[!; 3]` is non-empty
-  --> $DIR/empty-types.rs:313:11
+  --> $DIR/empty-types.rs:322:11
    |
 LL |     match *x {}
    |           ^^
@@ -383,7 +397,7 @@ LL ~     }
    |
 
 error[E0004]: non-exhaustive patterns: type `&[!]` is non-empty
-  --> $DIR/empty-types.rs:318:11
+  --> $DIR/empty-types.rs:327:11
    |
 LL |     match slice_never {}
    |           ^^^^^^^^^^^
@@ -397,7 +411,7 @@ LL +     }
    |
 
 error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
-  --> $DIR/empty-types.rs:320:11
+  --> $DIR/empty-types.rs:329:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ pattern `&[_, ..]` not covered
@@ -411,7 +425,7 @@ LL +         &[_, ..] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[]`, `&[_]` and `&[_, _]` not covered
-  --> $DIR/empty-types.rs:329:11
+  --> $DIR/empty-types.rs:338:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ patterns `&[]`, `&[_]` and `&[_, _]` not covered
@@ -424,7 +438,7 @@ LL +         &[] | &[_] | &[_, _] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `&[]` and `&[_, ..]` not covered
-  --> $DIR/empty-types.rs:343:11
+  --> $DIR/empty-types.rs:352:11
    |
 LL |     match slice_never {
    |           ^^^^^^^^^^^ patterns `&[]` and `&[_, ..]` not covered
@@ -438,7 +452,7 @@ LL +         &[] | &[_, ..] => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: type `[!]` is non-empty
-  --> $DIR/empty-types.rs:350:11
+  --> $DIR/empty-types.rs:359:11
    |
 LL |     match *slice_never {}
    |           ^^^^^^^^^^^^
@@ -452,7 +466,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:359:9
+  --> $DIR/empty-types.rs:368:9
    |
 LL |         _ => {}
    |         ^
@@ -460,7 +474,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:362:9
+  --> $DIR/empty-types.rs:371:9
    |
 LL |         [_, _, _] => {}
    |         ^^^^^^^^^
@@ -468,7 +482,7 @@ LL |         [_, _, _] => {}
    = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:365:9
+  --> $DIR/empty-types.rs:374:9
    |
 LL |         [_, ..] => {}
    |         ^^^^^^^
@@ -476,7 +490,7 @@ LL |         [_, ..] => {}
    = note: this pattern matches no values because `[!; 3]` is uninhabited
 
 error[E0004]: non-exhaustive patterns: type `[!; 0]` is non-empty
-  --> $DIR/empty-types.rs:379:11
+  --> $DIR/empty-types.rs:388:11
    |
 LL |     match array_0_never {}
    |           ^^^^^^^^^^^^^
@@ -490,7 +504,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:386:9
+  --> $DIR/empty-types.rs:395:9
    |
 LL |         [] => {}
    |         -- matches all the values already
@@ -498,7 +512,7 @@ LL |         _ => {}
    |         ^ unreachable pattern
 
 error[E0004]: non-exhaustive patterns: `[]` not covered
-  --> $DIR/empty-types.rs:388:11
+  --> $DIR/empty-types.rs:397:11
    |
 LL |     match array_0_never {
    |           ^^^^^^^^^^^^^ pattern `[]` not covered
@@ -512,7 +526,7 @@ LL +         [] => todo!()
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:407:9
+  --> $DIR/empty-types.rs:416:9
    |
 LL |         Some(_) => {}
    |         ^^^^^^^
@@ -520,7 +534,7 @@ LL |         Some(_) => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:412:9
+  --> $DIR/empty-types.rs:421:9
    |
 LL |         Some(_a) => {}
    |         ^^^^^^^^
@@ -528,7 +542,7 @@ LL |         Some(_a) => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:417:9
+  --> $DIR/empty-types.rs:426:9
    |
 LL |         None => {}
    |         ---- matches all the values already
@@ -537,7 +551,7 @@ LL |         _ => {}
    |         ^ unreachable pattern
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:422:9
+  --> $DIR/empty-types.rs:431:9
    |
 LL |         None => {}
    |         ---- matches all the values already
@@ -546,7 +560,7 @@ LL |         _a => {}
    |         ^^ unreachable pattern
 
 error[E0004]: non-exhaustive patterns: `&Some(_)` not covered
-  --> $DIR/empty-types.rs:442:11
+  --> $DIR/empty-types.rs:451:11
    |
 LL |     match ref_opt_never {
    |           ^^^^^^^^^^^^^ pattern `&Some(_)` not covered
@@ -565,7 +579,7 @@ LL +         &Some(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `Some(_)` not covered
-  --> $DIR/empty-types.rs:483:11
+  --> $DIR/empty-types.rs:492:11
    |
 LL |     match *ref_opt_never {
    |           ^^^^^^^^^^^^^^ pattern `Some(_)` not covered
@@ -584,7 +598,7 @@ LL +         Some(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `Err(_)` not covered
-  --> $DIR/empty-types.rs:531:11
+  --> $DIR/empty-types.rs:540:11
    |
 LL |     match *ref_res_never {
    |           ^^^^^^^^^^^^^^ pattern `Err(_)` not covered
@@ -603,7 +617,7 @@ LL +         Err(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `Err(_)` not covered
-  --> $DIR/empty-types.rs:542:11
+  --> $DIR/empty-types.rs:551:11
    |
 LL |     match *ref_res_never {
    |           ^^^^^^^^^^^^^^ pattern `Err(_)` not covered
@@ -622,7 +636,7 @@ LL +         Err(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: type `(u32, !)` is non-empty
-  --> $DIR/empty-types.rs:561:11
+  --> $DIR/empty-types.rs:570:11
    |
 LL |     match *ref_tuple_half_never {}
    |           ^^^^^^^^^^^^^^^^^^^^^
@@ -636,7 +650,7 @@ LL +     }
    |
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:594:9
+  --> $DIR/empty-types.rs:603:9
    |
 LL |         _ => {}
    |         ^
@@ -644,7 +658,7 @@ LL |         _ => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:597:9
+  --> $DIR/empty-types.rs:606:9
    |
 LL |         _x => {}
    |         ^^
@@ -652,7 +666,7 @@ LL |         _x => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:600:9
+  --> $DIR/empty-types.rs:609:9
    |
 LL |         _ if false => {}
    |         ^
@@ -660,7 +674,7 @@ LL |         _ if false => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error: unreachable pattern
-  --> $DIR/empty-types.rs:603:9
+  --> $DIR/empty-types.rs:612:9
    |
 LL |         _x if false => {}
    |         ^^
@@ -668,7 +682,7 @@ LL |         _x if false => {}
    = note: this pattern matches no values because `!` is uninhabited
 
 error[E0004]: non-exhaustive patterns: `&_` not covered
-  --> $DIR/empty-types.rs:628:11
+  --> $DIR/empty-types.rs:637:11
    |
 LL |     match ref_never {
    |           ^^^^^^^^^ pattern `&_` not covered
@@ -684,7 +698,7 @@ LL +         &_ => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `Ok(_)` not covered
-  --> $DIR/empty-types.rs:644:11
+  --> $DIR/empty-types.rs:653:11
    |
 LL |     match *ref_result_never {
    |           ^^^^^^^^^^^^^^^^^ pattern `Ok(_)` not covered
@@ -703,7 +717,7 @@ LL +         Ok(_) => todo!()
    |
 
 error[E0004]: non-exhaustive patterns: `Some(_)` not covered
-  --> $DIR/empty-types.rs:664:11
+  --> $DIR/empty-types.rs:673:11
    |
 LL |     match *x {
    |           ^^ pattern `Some(_)` not covered
@@ -721,7 +735,7 @@ LL ~         None => {},
 LL +         Some(_) => todo!()
    |
 
-error: aborting due to 64 previous errors
+error: aborting due to 65 previous errors
 
 Some errors have detailed explanations: E0004, E0005.
 For more information about an error, try `rustc --explain E0004`.
diff --git a/tests/ui/pattern/usefulness/empty-types.rs b/tests/ui/pattern/usefulness/empty-types.rs
index 639c48cea12..d561a0e9c12 100644
--- a/tests/ui/pattern/usefulness/empty-types.rs
+++ b/tests/ui/pattern/usefulness/empty-types.rs
@@ -17,7 +17,7 @@
 #[derive(Copy, Clone)]
 enum Void {}
 
-/// A bunch of never situations that can't be normally constructed.
+/// A bunch of never situations that can't be normally constructed so we take them as argument.
 #[derive(Copy, Clone)]
 struct NeverBundle {
     never: !,
@@ -272,6 +272,8 @@ fn nested_validity_tracking(bundle: NeverBundle) {
     let ref_never: &! = &never;
     let tuple_never: (!, !) = bundle.tuple_never;
     let result_never: Result<!, !> = bundle.result_never;
+    let result_never_err: Result<u8, !> = Ok(0);
+    let ptr_result_never_err: *const Result<u8, !> = &result_never_err as *const _;
     let union_never = Uninit::<!>::new();
 
     // These should be considered known_valid and warn unreachable.
@@ -287,6 +289,13 @@ fn nested_validity_tracking(bundle: NeverBundle) {
     }
 
     // These should be considered !known_valid and not warn unreachable.
+    unsafe {
+        match *ptr_result_never_err {
+            Ok(_) => {}
+            Err(_) => {}
+        }
+        let Ok(_) = *ptr_result_never_err; //[normal,never_pats]~ ERROR refutable pattern
+    }
     match ref_never {
         &_ => {}
     }