From 9d1f790594cc58187aaca5cb64b4e324b331a565 Mon Sep 17 00:00:00 2001
From: Urgau <urgau@numericable.fr>
Date: Thu, 9 Nov 2023 17:37:27 +0100
Subject: [PATCH 01/21] Add warn-by-default lint against unpredictable fn
 pointer comparisons

---
 compiler/rustc_lint/messages.ftl              |   6 +
 compiler/rustc_lint/src/lints.rs              |  36 ++++
 compiler/rustc_lint/src/types.rs              | 138 +++++++++++++-
 tests/ui/lint/fn-ptr-comparisons-weird.rs     |  15 ++
 tests/ui/lint/fn-ptr-comparisons-weird.stderr |  43 +++++
 tests/ui/lint/fn-ptr-comparisons.fixed        |  58 ++++++
 tests/ui/lint/fn-ptr-comparisons.rs           |  58 ++++++
 tests/ui/lint/fn-ptr-comparisons.stderr       | 171 ++++++++++++++++++
 8 files changed, 521 insertions(+), 4 deletions(-)
 create mode 100644 tests/ui/lint/fn-ptr-comparisons-weird.rs
 create mode 100644 tests/ui/lint/fn-ptr-comparisons-weird.stderr
 create mode 100644 tests/ui/lint/fn-ptr-comparisons.fixed
 create mode 100644 tests/ui/lint/fn-ptr-comparisons.rs
 create mode 100644 tests/ui/lint/fn-ptr-comparisons.stderr

diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 4aeaf61681604..54039d56929cf 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -882,6 +882,12 @@ lint_unnameable_test_items = cannot test inner items
 lint_unnecessary_qualification = unnecessary qualification
     .suggestion = remove the unnecessary path segments
 
+lint_unpredictable_fn_pointer_comparisons = function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+    .note_duplicated_fn = the address of the same function can vary between different codegen units
+    .note_deduplicated_fn = furthermore, different functions could have the same address after being merged together
+    .note_visit_fn_addr_eq = for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+    .fn_addr_eq_suggestion = refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
+
 lint_unqualified_local_imports = `use` of a local item without leading `self::`, `super::`, or `crate::`
 
 lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 3a854796f6735..5721ef644da4c 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1810,6 +1810,42 @@ pub(crate) enum AmbiguousWidePointerComparisonsAddrSuggestion<'a> {
     },
 }
 
+#[derive(LintDiagnostic)]
+pub(crate) enum UnpredictableFunctionPointerComparisons<'a> {
+    #[diag(lint_unpredictable_fn_pointer_comparisons)]
+    #[note(lint_note_duplicated_fn)]
+    #[note(lint_note_deduplicated_fn)]
+    #[note(lint_note_visit_fn_addr_eq)]
+    Suggestion {
+        #[subdiagnostic]
+        sugg: UnpredictableFunctionPointerComparisonsSuggestion<'a>,
+    },
+    #[diag(lint_unpredictable_fn_pointer_comparisons)]
+    #[note(lint_note_duplicated_fn)]
+    #[note(lint_note_deduplicated_fn)]
+    #[note(lint_note_visit_fn_addr_eq)]
+    Warn,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    lint_fn_addr_eq_suggestion,
+    style = "verbose",
+    applicability = "maybe-incorrect"
+)]
+pub(crate) struct UnpredictableFunctionPointerComparisonsSuggestion<'a> {
+    pub ne: &'a str,
+    pub cast_right: String,
+    pub deref_left: &'a str,
+    pub deref_right: &'a str,
+    #[suggestion_part(code = "{ne}std::ptr::fn_addr_eq({deref_left}")]
+    pub left: Span,
+    #[suggestion_part(code = ", {deref_right}")]
+    pub middle: Span,
+    #[suggestion_part(code = "{cast_right})")]
+    pub right: Span,
+}
+
 pub(crate) struct ImproperCTypes<'a> {
     pub ty: Ty<'a>,
     pub desc: &'a str,
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index b1d7d4ab68951..33650be056dd1 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -23,7 +23,9 @@ use crate::lints::{
     AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion,
     AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
     AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons,
-    InvalidNanComparisonsSuggestion, UnusedComparisons, VariantSizeDifferencesDiag,
+    InvalidNanComparisonsSuggestion, UnpredictableFunctionPointerComparisons,
+    UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons,
+    VariantSizeDifferencesDiag,
 };
 use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
 
@@ -166,6 +168,35 @@ declare_lint! {
     "detects ambiguous wide pointer comparisons"
 }
 
+declare_lint! {
+    /// The `unpredictable_function_pointer_comparisons` lint checks comparison
+    /// of function pointer as the operands.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// fn a() {}
+    /// fn b() {}
+    ///
+    /// let f: fn() = a;
+    /// let g: fn() = b;
+    ///
+    /// let _ = f == g;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Function pointers comparisons do not produce meaningful result since
+    /// they are never guaranteed to be unique and could vary between different
+    /// code generation units. Furthermore, different functions could have the
+    /// same address after being merged together.
+    UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS,
+    Warn,
+    "detects unpredictable function pointer comparisons"
+}
+
 #[derive(Copy, Clone, Default)]
 pub(crate) struct TypeLimits {
     /// Id of the last visited negated expression
@@ -178,7 +209,8 @@ impl_lint_pass!(TypeLimits => [
     UNUSED_COMPARISONS,
     OVERFLOWING_LITERALS,
     INVALID_NAN_COMPARISONS,
-    AMBIGUOUS_WIDE_POINTER_COMPARISONS
+    AMBIGUOUS_WIDE_POINTER_COMPARISONS,
+    UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS
 ]);
 
 impl TypeLimits {
@@ -255,7 +287,7 @@ fn lint_nan<'tcx>(
     cx.emit_span_lint(INVALID_NAN_COMPARISONS, e.span, lint);
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Copy, Clone)]
 enum ComparisonOp {
     BinOp(hir::BinOpKind),
     Other,
@@ -383,6 +415,100 @@ fn lint_wide_pointer<'tcx>(
     );
 }
 
+fn lint_fn_pointer<'tcx>(
+    cx: &LateContext<'tcx>,
+    e: &'tcx hir::Expr<'tcx>,
+    cmpop: ComparisonOp,
+    l: &'tcx hir::Expr<'tcx>,
+    r: &'tcx hir::Expr<'tcx>,
+) {
+    let peel_refs = |mut ty: Ty<'tcx>| -> (Ty<'tcx>, usize) {
+        let mut refs = 0;
+
+        while let ty::Ref(_, inner_ty, _) = ty.kind() {
+            ty = *inner_ty;
+            refs += 1;
+        }
+
+        (ty, refs)
+    };
+
+    // Left and right operands can have borrows, remove them
+    let l = l.peel_borrows();
+    let r = r.peel_borrows();
+
+    let Some(l_ty) = cx.typeck_results().expr_ty_opt(l) else { return };
+    let Some(r_ty) = cx.typeck_results().expr_ty_opt(r) else { return };
+
+    // Remove any references as `==` will deref through them (and count the
+    // number of references removed, for latter).
+    let (l_ty, l_ty_refs) = peel_refs(l_ty);
+    let (r_ty, r_ty_refs) = peel_refs(r_ty);
+
+    if !l_ty.is_fn() || !r_ty.is_fn() {
+        return;
+    }
+
+    // Let's try to suggest `ptr::fn_addr_eq` if/when possible.
+
+    let is_eq_ne = matches!(cmpop, ComparisonOp::BinOp(hir::BinOpKind::Eq | hir::BinOpKind::Ne));
+
+    if !is_eq_ne {
+        // Neither `==` nor `!=`, we can't suggest `ptr::fn_addr_eq`, just show the warning.
+        return cx.emit_span_lint(
+            UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS,
+            e.span,
+            UnpredictableFunctionPointerComparisons::Warn,
+        );
+    }
+
+    let (Some(l_span), Some(r_span)) =
+        (l.span.find_ancestor_inside(e.span), r.span.find_ancestor_inside(e.span))
+    else {
+        // No appropriate spans for the left and right operands, just show the warning.
+        return cx.emit_span_lint(
+            UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS,
+            e.span,
+            UnpredictableFunctionPointerComparisons::Warn,
+        );
+    };
+
+    let ne = if cmpop == ComparisonOp::BinOp(hir::BinOpKind::Ne) { "!" } else { "" };
+
+    // `ptr::fn_addr_eq` only works with raw pointer, deref any references.
+    let deref_left = &*"*".repeat(l_ty_refs);
+    let deref_right = &*"*".repeat(r_ty_refs);
+
+    let left = e.span.shrink_to_lo().until(l_span.shrink_to_lo());
+    let middle = l_span.shrink_to_hi().until(r_span.shrink_to_lo());
+    let right = r_span.shrink_to_hi().until(e.span.shrink_to_hi());
+
+    // We only check for a right cast as `FnDef` == `FnPtr` is not possible,
+    // only `FnPtr == FnDef` is possible.
+    let cast_right = if !r_ty.is_fn_ptr() {
+        let fn_sig = r_ty.fn_sig(cx.tcx);
+        format!(" as {fn_sig}")
+    } else {
+        String::new()
+    };
+
+    cx.emit_span_lint(
+        UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS,
+        e.span,
+        UnpredictableFunctionPointerComparisons::Suggestion {
+            sugg: UnpredictableFunctionPointerComparisonsSuggestion {
+                ne,
+                deref_left,
+                deref_right,
+                left,
+                middle,
+                right,
+                cast_right,
+            },
+        },
+    );
+}
+
 impl<'tcx> LateLintPass<'tcx> for TypeLimits {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) {
         match e.kind {
@@ -399,7 +525,9 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
                         cx.emit_span_lint(UNUSED_COMPARISONS, e.span, UnusedComparisons);
                     } else {
                         lint_nan(cx, e, binop, l, r);
-                        lint_wide_pointer(cx, e, ComparisonOp::BinOp(binop.node), l, r);
+                        let cmpop = ComparisonOp::BinOp(binop.node);
+                        lint_wide_pointer(cx, e, cmpop, l, r);
+                        lint_fn_pointer(cx, e, cmpop, l, r);
                     }
                 }
             }
@@ -411,6 +539,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
                     && let Some(cmpop) = diag_item_cmpop(diag_item) =>
             {
                 lint_wide_pointer(cx, e, cmpop, l, r);
+                lint_fn_pointer(cx, e, cmpop, l, r);
             }
             hir::ExprKind::MethodCall(_, l, [r], _)
                 if let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
@@ -418,6 +547,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
                     && let Some(cmpop) = diag_item_cmpop(diag_item) =>
             {
                 lint_wide_pointer(cx, e, cmpop, l, r);
+                lint_fn_pointer(cx, e, cmpop, l, r);
             }
             _ => {}
         };
diff --git a/tests/ui/lint/fn-ptr-comparisons-weird.rs b/tests/ui/lint/fn-ptr-comparisons-weird.rs
new file mode 100644
index 0000000000000..171fbfb87279d
--- /dev/null
+++ b/tests/ui/lint/fn-ptr-comparisons-weird.rs
@@ -0,0 +1,15 @@
+//@ check-pass
+
+fn main() {
+    let f: fn() = main;
+    let g: fn() = main;
+
+    let _ = f > g;
+    //~^ WARN function pointer comparisons
+    let _ = f >= g;
+    //~^ WARN function pointer comparisons
+    let _ = f <= g;
+    //~^ WARN function pointer comparisons
+    let _ = f < g;
+    //~^ WARN function pointer comparisons
+}
diff --git a/tests/ui/lint/fn-ptr-comparisons-weird.stderr b/tests/ui/lint/fn-ptr-comparisons-weird.stderr
new file mode 100644
index 0000000000000..f237166392238
--- /dev/null
+++ b/tests/ui/lint/fn-ptr-comparisons-weird.stderr
@@ -0,0 +1,43 @@
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons-weird.rs:7:13
+   |
+LL |     let _ = f > g;
+   |             ^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+   = note: `#[warn(unpredictable_function_pointer_comparisons)]` on by default
+
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons-weird.rs:9:13
+   |
+LL |     let _ = f >= g;
+   |             ^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons-weird.rs:11:13
+   |
+LL |     let _ = f <= g;
+   |             ^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons-weird.rs:13:13
+   |
+LL |     let _ = f < g;
+   |             ^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+
+warning: 4 warnings emitted
+
diff --git a/tests/ui/lint/fn-ptr-comparisons.fixed b/tests/ui/lint/fn-ptr-comparisons.fixed
new file mode 100644
index 0000000000000..22f16177a0446
--- /dev/null
+++ b/tests/ui/lint/fn-ptr-comparisons.fixed
@@ -0,0 +1,58 @@
+//@ check-pass
+//@ run-rustfix
+
+extern "C" {
+    fn test();
+}
+
+fn a() {}
+
+extern "C" fn c() {}
+
+extern "C" fn args(_a: i32) -> i32 { 0 }
+
+#[derive(PartialEq, Eq)]
+struct A {
+    f: fn(),
+}
+
+fn main() {
+    let f: fn() = a;
+    let g: fn() = f;
+
+    let a1 = A { f };
+    let a2 = A { f };
+
+    let _ = std::ptr::fn_addr_eq(f, a as fn());
+    //~^ WARN function pointer comparisons
+    let _ = !std::ptr::fn_addr_eq(f, a as fn());
+    //~^ WARN function pointer comparisons
+    let _ = std::ptr::fn_addr_eq(f, g);
+    //~^ WARN function pointer comparisons
+    let _ = std::ptr::fn_addr_eq(f, f);
+    //~^ WARN function pointer comparisons
+    let _ = std::ptr::fn_addr_eq(g, g);
+    //~^ WARN function pointer comparisons
+    let _ = std::ptr::fn_addr_eq(g, g);
+    //~^ WARN function pointer comparisons
+    let _ = std::ptr::fn_addr_eq(g, g);
+    //~^ WARN function pointer comparisons
+    let _ = std::ptr::fn_addr_eq(a as fn(), g);
+    //~^ WARN function pointer comparisons
+
+    let cfn: extern "C" fn() = c;
+    let _ = std::ptr::fn_addr_eq(cfn, c as extern "C" fn());
+    //~^ WARN function pointer comparisons
+
+    let argsfn: extern "C" fn(i32) -> i32 = args;
+    let _ = std::ptr::fn_addr_eq(argsfn, args as extern "C" fn(i32) -> i32);
+    //~^ WARN function pointer comparisons
+
+    let t: unsafe extern "C" fn() = test;
+    let _ = std::ptr::fn_addr_eq(t, test as unsafe extern "C" fn());
+    //~^ WARN function pointer comparisons
+
+    let _ = a1 == a2; // should not warn
+    let _ = std::ptr::fn_addr_eq(a1.f, a2.f);
+    //~^ WARN function pointer comparisons
+}
diff --git a/tests/ui/lint/fn-ptr-comparisons.rs b/tests/ui/lint/fn-ptr-comparisons.rs
new file mode 100644
index 0000000000000..90a8ab5c926b6
--- /dev/null
+++ b/tests/ui/lint/fn-ptr-comparisons.rs
@@ -0,0 +1,58 @@
+//@ check-pass
+//@ run-rustfix
+
+extern "C" {
+    fn test();
+}
+
+fn a() {}
+
+extern "C" fn c() {}
+
+extern "C" fn args(_a: i32) -> i32 { 0 }
+
+#[derive(PartialEq, Eq)]
+struct A {
+    f: fn(),
+}
+
+fn main() {
+    let f: fn() = a;
+    let g: fn() = f;
+
+    let a1 = A { f };
+    let a2 = A { f };
+
+    let _ = f == a;
+    //~^ WARN function pointer comparisons
+    let _ = f != a;
+    //~^ WARN function pointer comparisons
+    let _ = f == g;
+    //~^ WARN function pointer comparisons
+    let _ = f == f;
+    //~^ WARN function pointer comparisons
+    let _ = g == g;
+    //~^ WARN function pointer comparisons
+    let _ = g == g;
+    //~^ WARN function pointer comparisons
+    let _ = &g == &g;
+    //~^ WARN function pointer comparisons
+    let _ = a as fn() == g;
+    //~^ WARN function pointer comparisons
+
+    let cfn: extern "C" fn() = c;
+    let _ = cfn == c;
+    //~^ WARN function pointer comparisons
+
+    let argsfn: extern "C" fn(i32) -> i32 = args;
+    let _ = argsfn == args;
+    //~^ WARN function pointer comparisons
+
+    let t: unsafe extern "C" fn() = test;
+    let _ = t == test;
+    //~^ WARN function pointer comparisons
+
+    let _ = a1 == a2; // should not warn
+    let _ = a1.f == a2.f;
+    //~^ WARN function pointer comparisons
+}
diff --git a/tests/ui/lint/fn-ptr-comparisons.stderr b/tests/ui/lint/fn-ptr-comparisons.stderr
new file mode 100644
index 0000000000000..eaba23a461ab6
--- /dev/null
+++ b/tests/ui/lint/fn-ptr-comparisons.stderr
@@ -0,0 +1,171 @@
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons.rs:26:13
+   |
+LL |     let _ = f == a;
+   |             ^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+   = note: `#[warn(unpredictable_function_pointer_comparisons)]` on by default
+help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
+   |
+LL |     let _ = std::ptr::fn_addr_eq(f, a as fn());
+   |             +++++++++++++++++++++ ~   ++++++++
+
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons.rs:28:13
+   |
+LL |     let _ = f != a;
+   |             ^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
+   |
+LL |     let _ = !std::ptr::fn_addr_eq(f, a as fn());
+   |             ++++++++++++++++++++++ ~   ++++++++
+
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons.rs:30:13
+   |
+LL |     let _ = f == g;
+   |             ^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
+   |
+LL |     let _ = std::ptr::fn_addr_eq(f, g);
+   |             +++++++++++++++++++++ ~  +
+
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons.rs:32:13
+   |
+LL |     let _ = f == f;
+   |             ^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
+   |
+LL |     let _ = std::ptr::fn_addr_eq(f, f);
+   |             +++++++++++++++++++++ ~  +
+
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons.rs:34:13
+   |
+LL |     let _ = g == g;
+   |             ^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
+   |
+LL |     let _ = std::ptr::fn_addr_eq(g, g);
+   |             +++++++++++++++++++++ ~  +
+
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons.rs:36:13
+   |
+LL |     let _ = g == g;
+   |             ^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
+   |
+LL |     let _ = std::ptr::fn_addr_eq(g, g);
+   |             +++++++++++++++++++++ ~  +
+
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons.rs:38:13
+   |
+LL |     let _ = &g == &g;
+   |             ^^^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
+   |
+LL |     let _ = std::ptr::fn_addr_eq(g, g);
+   |             ~~~~~~~~~~~~~~~~~~~~~ ~  +
+
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons.rs:40:13
+   |
+LL |     let _ = a as fn() == g;
+   |             ^^^^^^^^^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
+   |
+LL |     let _ = std::ptr::fn_addr_eq(a as fn(), g);
+   |             +++++++++++++++++++++         ~  +
+
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons.rs:44:13
+   |
+LL |     let _ = cfn == c;
+   |             ^^^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
+   |
+LL |     let _ = std::ptr::fn_addr_eq(cfn, c as extern "C" fn());
+   |             +++++++++++++++++++++   ~   +++++++++++++++++++
+
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons.rs:48:13
+   |
+LL |     let _ = argsfn == args;
+   |             ^^^^^^^^^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
+   |
+LL |     let _ = std::ptr::fn_addr_eq(argsfn, args as extern "C" fn(i32) -> i32);
+   |             +++++++++++++++++++++      ~      +++++++++++++++++++++++++++++
+
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons.rs:52:13
+   |
+LL |     let _ = t == test;
+   |             ^^^^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
+   |
+LL |     let _ = std::ptr::fn_addr_eq(t, test as unsafe extern "C" fn());
+   |             +++++++++++++++++++++ ~      ++++++++++++++++++++++++++
+
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons.rs:56:13
+   |
+LL |     let _ = a1.f == a2.f;
+   |             ^^^^^^^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+help: refactor your code, or use `std::ptr::fn_addr_eq` to suppress the lint
+   |
+LL |     let _ = std::ptr::fn_addr_eq(a1.f, a2.f);
+   |             +++++++++++++++++++++    ~     +
+
+warning: 12 warnings emitted
+

From 5e34c2e43c9110ac91579cb1b6d44ebdba0b5712 Mon Sep 17 00:00:00 2001
From: Urgau <urgau@numericable.fr>
Date: Sun, 10 Dec 2023 18:16:53 +0100
Subject: [PATCH 02/21] Drop uplifted `clippy::fn_address_comparisons`

---
 .../clippy/clippy_lints/src/declared_lints.rs |   1 -
 .../clippy_lints/src/deprecated_lints.rs      |   2 +
 src/tools/clippy/clippy_lints/src/lib.rs      |   2 -
 .../clippy_lints/src/unnamed_address.rs       |  60 --------
 .../clippy/tests/ui/fn_address_comparisons.rs |  23 ---
 .../tests/ui/fn_address_comparisons.stderr    |  17 ---
 src/tools/clippy/tests/ui/rename.fixed        |   2 +
 src/tools/clippy/tests/ui/rename.rs           |   2 +
 src/tools/clippy/tests/ui/rename.stderr       | 140 +++++++++---------
 9 files changed, 79 insertions(+), 170 deletions(-)
 delete mode 100644 src/tools/clippy/clippy_lints/src/unnamed_address.rs
 delete mode 100644 src/tools/clippy/tests/ui/fn_address_comparisons.rs
 delete mode 100644 src/tools/clippy/tests/ui/fn_address_comparisons.stderr

diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index c4a0c8f186510..022ed180ed8ca 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -744,7 +744,6 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::unit_types::LET_UNIT_VALUE_INFO,
     crate::unit_types::UNIT_ARG_INFO,
     crate::unit_types::UNIT_CMP_INFO,
-    crate::unnamed_address::FN_ADDRESS_COMPARISONS_INFO,
     crate::unnecessary_box_returns::UNNECESSARY_BOX_RETURNS_INFO,
     crate::unnecessary_literal_bound::UNNECESSARY_LITERAL_BOUND_INFO,
     crate::unnecessary_map_on_constructor::UNNECESSARY_MAP_ON_CONSTRUCTOR_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index 77dbe9b78a182..3ea792d8b835c 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -74,6 +74,8 @@ declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[
     #[clippy::version = "1.53.0"]
     ("clippy::filter_map", "clippy::manual_filter_map"),
     #[clippy::version = ""]
+    ("clippy::fn_address_comparisons", "unpredictable_function_pointer_comparisons"),
+    #[clippy::version = ""]
     ("clippy::identity_conversion", "clippy::useless_conversion"),
     #[clippy::version = "pre 1.29.0"]
     ("clippy::if_let_redundant_pattern_matching", "clippy::redundant_pattern_matching"),
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index c9064df25ac89..e80cca6e7db4b 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -363,7 +363,6 @@ mod uninhabited_references;
 mod uninit_vec;
 mod unit_return_expecting_ord;
 mod unit_types;
-mod unnamed_address;
 mod unnecessary_box_returns;
 mod unnecessary_literal_bound;
 mod unnecessary_map_on_constructor;
@@ -786,7 +785,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap));
     store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(conf)));
     store.register_late_pass(|_| Box::<redundant_pub_crate::RedundantPubCrate>::default());
-    store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress));
     store.register_late_pass(|_| Box::<dereference::Dereferencing<'_>>::default());
     store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse));
     store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend));
diff --git a/src/tools/clippy/clippy_lints/src/unnamed_address.rs b/src/tools/clippy/clippy_lints/src/unnamed_address.rs
deleted file mode 100644
index cd2dacc9f099c..0000000000000
--- a/src/tools/clippy/clippy_lints/src/unnamed_address.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-use clippy_utils::diagnostics::span_lint;
-use rustc_hir::{BinOpKind, Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
-use rustc_session::declare_lint_pass;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for comparisons with an address of a function item.
-    ///
-    /// ### Why is this bad?
-    /// Function item address is not guaranteed to be unique and could vary
-    /// between different code generation units. Furthermore different function items could have
-    /// the same address after being merged together.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// type F = fn();
-    /// fn a() {}
-    /// let f: F = a;
-    /// if f == a {
-    ///     // ...
-    /// }
-    /// ```
-    #[clippy::version = "1.44.0"]
-    pub FN_ADDRESS_COMPARISONS,
-    correctness,
-    "comparison with an address of a function item"
-}
-
-declare_lint_pass!(UnnamedAddress => [FN_ADDRESS_COMPARISONS]);
-
-impl LateLintPass<'_> for UnnamedAddress {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        fn is_comparison(binop: BinOpKind) -> bool {
-            matches!(
-                binop,
-                BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ne | BinOpKind::Ge | BinOpKind::Gt
-            )
-        }
-
-        fn is_fn_def(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-            matches!(cx.typeck_results().expr_ty(expr).kind(), ty::FnDef(..))
-        }
-
-        if let ExprKind::Binary(binop, left, right) = expr.kind
-            && is_comparison(binop.node)
-            && cx.typeck_results().expr_ty_adjusted(left).is_fn_ptr()
-            && cx.typeck_results().expr_ty_adjusted(right).is_fn_ptr()
-            && (is_fn_def(cx, left) || is_fn_def(cx, right))
-        {
-            span_lint(
-                cx,
-                FN_ADDRESS_COMPARISONS,
-                expr.span,
-                "comparing with a non-unique address of a function item",
-            );
-        }
-    }
-}
diff --git a/src/tools/clippy/tests/ui/fn_address_comparisons.rs b/src/tools/clippy/tests/ui/fn_address_comparisons.rs
deleted file mode 100644
index 35535bd4fddd0..0000000000000
--- a/src/tools/clippy/tests/ui/fn_address_comparisons.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-use std::fmt::Debug;
-use std::ptr;
-use std::rc::Rc;
-use std::sync::Arc;
-
-fn a() {}
-
-#[warn(clippy::fn_address_comparisons)]
-fn main() {
-    type F = fn();
-    let f: F = a;
-    let g: F = f;
-
-    // These should fail:
-    let _ = f == a;
-    //~^ ERROR: comparing with a non-unique address of a function item
-    //~| NOTE: `-D clippy::fn-address-comparisons` implied by `-D warnings`
-    let _ = f != a;
-    //~^ ERROR: comparing with a non-unique address of a function item
-
-    // These should be fine:
-    let _ = f == g;
-}
diff --git a/src/tools/clippy/tests/ui/fn_address_comparisons.stderr b/src/tools/clippy/tests/ui/fn_address_comparisons.stderr
deleted file mode 100644
index e6de7e358075d..0000000000000
--- a/src/tools/clippy/tests/ui/fn_address_comparisons.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error: comparing with a non-unique address of a function item
-  --> tests/ui/fn_address_comparisons.rs:15:13
-   |
-LL |     let _ = f == a;
-   |             ^^^^^^
-   |
-   = note: `-D clippy::fn-address-comparisons` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::fn_address_comparisons)]`
-
-error: comparing with a non-unique address of a function item
-  --> tests/ui/fn_address_comparisons.rs:18:13
-   |
-LL |     let _ = f != a;
-   |             ^^^^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 0d6e07aa546cf..47149622ef7c6 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -59,6 +59,7 @@
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
 #![allow(ambiguous_wide_pointer_comparisons)]
+#![allow(unpredictable_function_pointer_comparisons)]
 #![allow(clippy::reversed_empty_ranges)]
 #![warn(clippy::almost_complete_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
 #![warn(clippy::disallowed_names)] //~ ERROR: lint `clippy::blacklisted_name`
@@ -74,6 +75,7 @@
 #![warn(clippy::mixed_read_write_in_expression)] //~ ERROR: lint `clippy::eval_order_dependence`
 #![warn(clippy::manual_find_map)] //~ ERROR: lint `clippy::find_map`
 #![warn(clippy::manual_filter_map)] //~ ERROR: lint `clippy::filter_map`
+#![warn(unpredictable_function_pointer_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
 #![warn(clippy::useless_conversion)] //~ ERROR: lint `clippy::identity_conversion`
 #![warn(clippy::redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching`
 #![warn(clippy::match_result_ok)] //~ ERROR: lint `clippy::if_let_some_result`
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 2ac59718786b6..7a78a5d280ddb 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -59,6 +59,7 @@
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
 #![allow(ambiguous_wide_pointer_comparisons)]
+#![allow(unpredictable_function_pointer_comparisons)]
 #![allow(clippy::reversed_empty_ranges)]
 #![warn(clippy::almost_complete_letter_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
 #![warn(clippy::blacklisted_name)] //~ ERROR: lint `clippy::blacklisted_name`
@@ -74,6 +75,7 @@
 #![warn(clippy::eval_order_dependence)] //~ ERROR: lint `clippy::eval_order_dependence`
 #![warn(clippy::find_map)] //~ ERROR: lint `clippy::find_map`
 #![warn(clippy::filter_map)] //~ ERROR: lint `clippy::filter_map`
+#![warn(clippy::fn_address_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
 #![warn(clippy::identity_conversion)] //~ ERROR: lint `clippy::identity_conversion`
 #![warn(clippy::if_let_redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching`
 #![warn(clippy::if_let_some_result)] //~ ERROR: lint `clippy::if_let_some_result`
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index a5ae727b7ee82..dc24bc16d0ea4 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> tests/ui/rename.rs:63:9
+  --> tests/ui/rename.rs:64:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -8,394 +8,400 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> tests/ui/rename.rs:64:9
+  --> tests/ui/rename.rs:65:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:65:9
+  --> tests/ui/rename.rs:66:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:66:9
+  --> tests/ui/rename.rs:67:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::blocks_in_if_conditions` has been renamed to `clippy::blocks_in_conditions`
-  --> tests/ui/rename.rs:67:9
+  --> tests/ui/rename.rs:68:9
    |
 LL | #![warn(clippy::blocks_in_if_conditions)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> tests/ui/rename.rs:68:9
+  --> tests/ui/rename.rs:69:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> tests/ui/rename.rs:69:9
+  --> tests/ui/rename.rs:70:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> tests/ui/rename.rs:70:9
+  --> tests/ui/rename.rs:71:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> tests/ui/rename.rs:71:9
+  --> tests/ui/rename.rs:72:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> tests/ui/rename.rs:72:9
+  --> tests/ui/rename.rs:73:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> tests/ui/rename.rs:73:9
+  --> tests/ui/rename.rs:74:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> tests/ui/rename.rs:74:9
+  --> tests/ui/rename.rs:75:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map`
-  --> tests/ui/rename.rs:75:9
+  --> tests/ui/rename.rs:76:9
    |
 LL | #![warn(clippy::find_map)]
    |         ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map`
 
 error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map`
-  --> tests/ui/rename.rs:76:9
+  --> tests/ui/rename.rs:77:9
    |
 LL | #![warn(clippy::filter_map)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map`
 
+error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons`
+  --> tests/ui/rename.rs:78:9
+   |
+LL | #![warn(clippy::fn_address_comparisons)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons`
+
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> tests/ui/rename.rs:77:9
+  --> tests/ui/rename.rs:79:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching`
-  --> tests/ui/rename.rs:78:9
+  --> tests/ui/rename.rs:80:9
    |
 LL | #![warn(clippy::if_let_redundant_pattern_matching)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> tests/ui/rename.rs:79:9
+  --> tests/ui/rename.rs:81:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl`
-  --> tests/ui/rename.rs:80:9
+  --> tests/ui/rename.rs:82:9
    |
 LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl`
 
 error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl`
-  --> tests/ui/rename.rs:81:9
+  --> tests/ui/rename.rs:83:9
    |
 LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl`
 
 error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
-  --> tests/ui/rename.rs:82:9
+  --> tests/ui/rename.rs:84:9
    |
 LL | #![warn(clippy::integer_arithmetic)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> tests/ui/rename.rs:83:9
+  --> tests/ui/rename.rs:85:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> tests/ui/rename.rs:84:9
+  --> tests/ui/rename.rs:86:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> tests/ui/rename.rs:85:9
+  --> tests/ui/rename.rs:87:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> tests/ui/rename.rs:86:9
+  --> tests/ui/rename.rs:88:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:87:9
+  --> tests/ui/rename.rs:89:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:88:9
+  --> tests/ui/rename.rs:90:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> tests/ui/rename.rs:89:9
+  --> tests/ui/rename.rs:91:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks`
-  --> tests/ui/rename.rs:90:9
+  --> tests/ui/rename.rs:92:9
    |
 LL | #![warn(clippy::overflow_check_conditional)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> tests/ui/rename.rs:91:9
+  --> tests/ui/rename.rs:93:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> tests/ui/rename.rs:92:9
+  --> tests/ui/rename.rs:94:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> tests/ui/rename.rs:93:9
+  --> tests/ui/rename.rs:95:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> tests/ui/rename.rs:94:9
+  --> tests/ui/rename.rs:96:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> tests/ui/rename.rs:95:9
+  --> tests/ui/rename.rs:97:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> tests/ui/rename.rs:96:9
+  --> tests/ui/rename.rs:98:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local`
-  --> tests/ui/rename.rs:97:9
+  --> tests/ui/rename.rs:99:9
    |
 LL | #![warn(clippy::thread_local_initializer_can_be_made_const)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> tests/ui/rename.rs:98:9
+  --> tests/ui/rename.rs:100:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
-  --> tests/ui/rename.rs:99:9
+  --> tests/ui/rename.rs:101:9
    |
 LL | #![warn(clippy::unwrap_or_else_default)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> tests/ui/rename.rs:100:9
+  --> tests/ui/rename.rs:102:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
-  --> tests/ui/rename.rs:101:9
+  --> tests/ui/rename.rs:103:9
    |
 LL | #![warn(clippy::cast_ref_to_mut)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> tests/ui/rename.rs:102:9
+  --> tests/ui/rename.rs:104:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
-  --> tests/ui/rename.rs:103:9
+  --> tests/ui/rename.rs:105:9
    |
 LL | #![warn(clippy::cmp_nan)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> tests/ui/rename.rs:104:9
+  --> tests/ui/rename.rs:106:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
-  --> tests/ui/rename.rs:105:9
+  --> tests/ui/rename.rs:107:9
    |
 LL | #![warn(clippy::drop_copy)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
 
 error: lint `clippy::drop_ref` has been renamed to `dropping_references`
-  --> tests/ui/rename.rs:106:9
+  --> tests/ui/rename.rs:108:9
    |
 LL | #![warn(clippy::drop_ref)]
    |         ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
 
 error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
-  --> tests/ui/rename.rs:107:9
+  --> tests/ui/rename.rs:109:9
    |
 LL | #![warn(clippy::fn_null_check)]
    |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:108:9
+  --> tests/ui/rename.rs:110:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:109:9
+  --> tests/ui/rename.rs:111:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> tests/ui/rename.rs:110:9
+  --> tests/ui/rename.rs:112:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
-  --> tests/ui/rename.rs:111:9
+  --> tests/ui/rename.rs:113:9
    |
 LL | #![warn(clippy::forget_copy)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
 
 error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
-  --> tests/ui/rename.rs:112:9
+  --> tests/ui/rename.rs:114:9
    |
 LL | #![warn(clippy::forget_ref)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> tests/ui/rename.rs:113:9
+  --> tests/ui/rename.rs:115:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> tests/ui/rename.rs:114:9
+  --> tests/ui/rename.rs:116:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> tests/ui/rename.rs:115:9
+  --> tests/ui/rename.rs:117:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
-  --> tests/ui/rename.rs:116:9
+  --> tests/ui/rename.rs:118:9
    |
 LL | #![warn(clippy::invalid_utf8_in_unchecked)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> tests/ui/rename.rs:117:9
+  --> tests/ui/rename.rs:119:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::maybe_misused_cfg` has been renamed to `unexpected_cfgs`
-  --> tests/ui/rename.rs:118:9
+  --> tests/ui/rename.rs:120:9
    |
 LL | #![warn(clippy::maybe_misused_cfg)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> tests/ui/rename.rs:119:9
+  --> tests/ui/rename.rs:121:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::mismatched_target_os` has been renamed to `unexpected_cfgs`
-  --> tests/ui/rename.rs:120:9
+  --> tests/ui/rename.rs:122:9
    |
 LL | #![warn(clippy::mismatched_target_os)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unexpected_cfgs`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> tests/ui/rename.rs:121:9
+  --> tests/ui/rename.rs:123:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> tests/ui/rename.rs:122:9
+  --> tests/ui/rename.rs:124:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
-  --> tests/ui/rename.rs:123:9
+  --> tests/ui/rename.rs:125:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
 
 error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
-  --> tests/ui/rename.rs:124:9
+  --> tests/ui/rename.rs:126:9
    |
 LL | #![warn(clippy::undropped_manually_drops)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> tests/ui/rename.rs:125:9
+  --> tests/ui/rename.rs:127:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> tests/ui/rename.rs:126:9
+  --> tests/ui/rename.rs:128:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
 error: lint `clippy::vtable_address_comparisons` has been renamed to `ambiguous_wide_pointer_comparisons`
-  --> tests/ui/rename.rs:127:9
+  --> tests/ui/rename.rs:129:9
    |
 LL | #![warn(clippy::vtable_address_comparisons)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons`
 
 error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges`
-  --> tests/ui/rename.rs:128:9
+  --> tests/ui/rename.rs:130:9
    |
 LL | #![warn(clippy::reverse_range_loop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
 
-error: aborting due to 66 previous errors
+error: aborting due to 67 previous errors
 

From 8ce63576bddc95e99b54ebf8ec9da6f52a647ad2 Mon Sep 17 00:00:00 2001
From: Urgau <urgau@numericable.fr>
Date: Sun, 10 Dec 2023 15:51:06 +0100
Subject: [PATCH 03/21] Allow fn pointers comparisons lint in UI tests

---
 src/tools/miri/tests/pass/function_pointers.rs                 | 2 ++
 src/tools/miri/tests/pass/issues/issue-91636.rs                | 2 ++
 tests/ui/binop/binary-op-on-fn-ptr-eq.rs                       | 3 +++
 tests/ui/box/unit/unique-ffi-symbols.rs                        | 3 +++
 tests/ui/consts/const-extern-function.rs                       | 2 ++
 tests/ui/cross-crate/const-cross-crate-extern.rs               | 2 ++
 tests/ui/extern/extern-compare-with-return-type.rs             | 1 +
 tests/ui/extern/extern-take-value.rs                           | 2 ++
 .../function-pointer-comparison-issue-54685.rs                 | 2 ++
 tests/ui/issues/issue-54696.rs                                 | 2 ++
 .../mir/validate/issue-95978-validator-lifetime-comparison.rs  | 2 ++
 11 files changed, 23 insertions(+)

diff --git a/src/tools/miri/tests/pass/function_pointers.rs b/src/tools/miri/tests/pass/function_pointers.rs
index a5c4bc5e0d95b..7145be334a13e 100644
--- a/src/tools/miri/tests/pass/function_pointers.rs
+++ b/src/tools/miri/tests/pass/function_pointers.rs
@@ -1,3 +1,5 @@
+#![allow(unpredictable_function_pointer_comparisons)]
+
 use std::mem;
 
 trait Answer {
diff --git a/src/tools/miri/tests/pass/issues/issue-91636.rs b/src/tools/miri/tests/pass/issues/issue-91636.rs
index 00370165812f5..d0cadcd2c70a9 100644
--- a/src/tools/miri/tests/pass/issues/issue-91636.rs
+++ b/src/tools/miri/tests/pass/issues/issue-91636.rs
@@ -1,3 +1,5 @@
+#![allow(unpredictable_function_pointer_comparisons)]
+
 type BuiltIn = for<'a> fn(&str);
 
 struct Function {
diff --git a/tests/ui/binop/binary-op-on-fn-ptr-eq.rs b/tests/ui/binop/binary-op-on-fn-ptr-eq.rs
index a5ec63587f96e..47b79f3855f60 100644
--- a/tests/ui/binop/binary-op-on-fn-ptr-eq.rs
+++ b/tests/ui/binop/binary-op-on-fn-ptr-eq.rs
@@ -1,6 +1,9 @@
 //@ run-pass
 // Tests equality between supertype and subtype of a function
 // See the issue #91636
+
+#![allow(unpredictable_function_pointer_comparisons)]
+
 fn foo(_a: &str) {}
 
 fn main() {
diff --git a/tests/ui/box/unit/unique-ffi-symbols.rs b/tests/ui/box/unit/unique-ffi-symbols.rs
index 65a9a32b2bb0c..75877f8397efe 100644
--- a/tests/ui/box/unit/unique-ffi-symbols.rs
+++ b/tests/ui/box/unit/unique-ffi-symbols.rs
@@ -1,6 +1,9 @@
 //@ run-pass
 // We used to have a __rust_abi shim that resulted in duplicated symbols
 // whenever the item path wasn't enough to disambiguate between them.
+
+#![allow(unpredictable_function_pointer_comparisons)]
+
 fn main() {
     let a = {
         extern "C" fn good() -> i32 { return 0; }
diff --git a/tests/ui/consts/const-extern-function.rs b/tests/ui/consts/const-extern-function.rs
index acc438189cb86..7629d63266acd 100644
--- a/tests/ui/consts/const-extern-function.rs
+++ b/tests/ui/consts/const-extern-function.rs
@@ -1,5 +1,7 @@
 //@ run-pass
+
 #![allow(non_upper_case_globals)]
+#![allow(unpredictable_function_pointer_comparisons)]
 
 extern "C" fn foopy() {}
 
diff --git a/tests/ui/cross-crate/const-cross-crate-extern.rs b/tests/ui/cross-crate/const-cross-crate-extern.rs
index 8d48a6a520606..0ec8753c30f2f 100644
--- a/tests/ui/cross-crate/const-cross-crate-extern.rs
+++ b/tests/ui/cross-crate/const-cross-crate-extern.rs
@@ -1,6 +1,8 @@
 //@ run-pass
 //@ aux-build:cci_const.rs
+
 #![allow(non_upper_case_globals)]
+#![allow(unpredictable_function_pointer_comparisons)]
 
 extern crate cci_const;
 use cci_const::bar;
diff --git a/tests/ui/extern/extern-compare-with-return-type.rs b/tests/ui/extern/extern-compare-with-return-type.rs
index 316e8b2fc7360..7d1027d5e776f 100644
--- a/tests/ui/extern/extern-compare-with-return-type.rs
+++ b/tests/ui/extern/extern-compare-with-return-type.rs
@@ -2,6 +2,7 @@
 
 // Tests that we can compare various kinds of extern fn signatures.
 #![allow(non_camel_case_types)]
+#![allow(unpredictable_function_pointer_comparisons)]
 
 // `dbg!()` differentiates these functions to ensure they won't be merged.
 extern "C" fn voidret1() { dbg!() }
diff --git a/tests/ui/extern/extern-take-value.rs b/tests/ui/extern/extern-take-value.rs
index 56ed3328614ce..f3df82b26109f 100644
--- a/tests/ui/extern/extern-take-value.rs
+++ b/tests/ui/extern/extern-take-value.rs
@@ -1,6 +1,8 @@
 //@ run-pass
 //@ aux-build:extern-take-value.rs
 
+#![allow(unpredictable_function_pointer_comparisons)]
+
 extern crate extern_take_value;
 
 pub fn main() {
diff --git a/tests/ui/function-pointer/function-pointer-comparison-issue-54685.rs b/tests/ui/function-pointer/function-pointer-comparison-issue-54685.rs
index 2e1c863e0f4ca..3ec958f2ebff2 100644
--- a/tests/ui/function-pointer/function-pointer-comparison-issue-54685.rs
+++ b/tests/ui/function-pointer/function-pointer-comparison-issue-54685.rs
@@ -1,6 +1,8 @@
 //@ compile-flags: -C opt-level=3
 //@ run-pass
 
+#![allow(unpredictable_function_pointer_comparisons)]
+
 fn foo(_i: i32) -> i32 {
     1
 }
diff --git a/tests/ui/issues/issue-54696.rs b/tests/ui/issues/issue-54696.rs
index 75b1824f0b383..63ffbe42bcc9f 100644
--- a/tests/ui/issues/issue-54696.rs
+++ b/tests/ui/issues/issue-54696.rs
@@ -1,5 +1,7 @@
 //@ run-pass
 
+#![allow(unpredictable_function_pointer_comparisons)]
+
 fn main() {
     // We shouldn't promote this
     let _ = &(main as fn() == main as fn());
diff --git a/tests/ui/mir/validate/issue-95978-validator-lifetime-comparison.rs b/tests/ui/mir/validate/issue-95978-validator-lifetime-comparison.rs
index 44b7fae351cd2..45d519739eba8 100644
--- a/tests/ui/mir/validate/issue-95978-validator-lifetime-comparison.rs
+++ b/tests/ui/mir/validate/issue-95978-validator-lifetime-comparison.rs
@@ -1,6 +1,8 @@
 //@ check-pass
 //@ compile-flags: -Zvalidate-mir
 
+#![allow(unpredictable_function_pointer_comparisons)]
+
 fn foo(_a: &str) {}
 
 fn main() {

From 7b06fcf55900cbc31c58d62793a40e808cefe68e Mon Sep 17 00:00:00 2001
From: Urgau <urgau@numericable.fr>
Date: Tue, 12 Dec 2023 13:10:13 +0100
Subject: [PATCH 04/21] Allow fn pointers comparisons lint in library

---
 library/core/tests/ptr.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index 7e9773f2fb952..454b13a7ee389 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -304,6 +304,7 @@ fn test_const_nonnull_new() {
 #[test]
 #[cfg(unix)] // printf may not be available on other platforms
 #[allow(deprecated)] // For SipHasher
+#[cfg_attr(not(bootstrap), allow(unpredictable_function_pointer_comparisons))]
 pub fn test_variadic_fnptr() {
     use core::ffi;
     use core::hash::{Hash, SipHasher};

From f613636ae87e7e973138c7cb3e850ec26f93c723 Mon Sep 17 00:00:00 2001
From: Oli Scherer <github333195615777966@oli-obk.de>
Date: Wed, 4 Dec 2024 16:01:31 +0000
Subject: [PATCH 05/21] Rename `core_pattern_type` and `core_pattern_types` lib
 feature  gates to `pattern_type_macro`

That's what the gates are actually gating, and the single char difference in naming was not helpful either
---
 library/core/src/lib.rs                       |  2 +-
 library/core/src/pat.rs                       |  2 +-
 library/std/src/lib.rs                        |  2 +-
 .../crates/ide-db/src/generated/lints.rs      | 13 ++----------
 tests/codegen/pattern_type_symbols.rs         |  3 +--
 .../bad_const_generics_args_on_const_param.rs |  2 +-
 tests/ui/type/pattern_types/bad_pat.rs        |  3 +--
 tests/ui/type/pattern_types/bad_pat.stderr    |  6 +++---
 tests/ui/type/pattern_types/const_generics.rs |  3 +--
 tests/ui/type/pattern_types/derives.rs        |  3 +--
 tests/ui/type/pattern_types/derives.stderr    |  2 +-
 .../feature-gate-pattern_types.rs             | 10 +++++-----
 .../feature-gate-pattern_types.stderr         | 20 +++++++++----------
 .../feature-gate-pattern_types2.rs            |  2 +-
 tests/ui/type/pattern_types/missing-is.rs     |  2 +-
 tests/ui/type/pattern_types/range_patterns.rs |  3 +--
 .../type/pattern_types/range_patterns.stderr  | 10 +++++-----
 .../range_patterns_inherent_impls.rs          |  3 +--
 .../range_patterns_inherent_impls.stderr      |  4 ++--
 .../range_patterns_trait_impls.rs             |  3 +--
 .../range_patterns_trait_impls2.rs            |  3 +--
 .../range_patterns_trait_impls2.stderr        |  2 +-
 .../pattern_types/range_patterns_unusable.rs  |  3 +--
 .../range_patterns_unusable.stderr            |  2 +-
 .../range_patterns_unusable_math.rs           |  3 +--
 .../range_patterns_unusable_math.stderr       |  2 +-
 .../pattern_types/range_patterns_usage.rs     |  3 +--
 .../type/pattern_types/unimplemented_pat.rs   |  3 +--
 .../pattern_types/unimplemented_pat.stderr    |  4 ++--
 tests/ui/unpretty/expanded-exhaustive.rs      |  2 +-
 tests/ui/unpretty/expanded-exhaustive.stdout  |  2 +-
 31 files changed, 53 insertions(+), 74 deletions(-)

diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index ab9c33ee75477..fde6887c5abae 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -345,7 +345,7 @@ pub mod net;
 pub mod option;
 pub mod panic;
 pub mod panicking;
-#[unstable(feature = "core_pattern_types", issue = "123646")]
+#[unstable(feature = "pattern_type_macro", issue = "123646")]
 pub mod pat;
 pub mod pin;
 #[unstable(feature = "random", issue = "130703")]
diff --git a/library/core/src/pat.rs b/library/core/src/pat.rs
index 1f89d960be67b..752e79c2dacee 100644
--- a/library/core/src/pat.rs
+++ b/library/core/src/pat.rs
@@ -6,7 +6,7 @@
 /// ```
 #[macro_export]
 #[rustc_builtin_macro(pattern_type)]
-#[unstable(feature = "core_pattern_type", issue = "123646")]
+#[unstable(feature = "pattern_type_macro", issue = "123646")]
 macro_rules! pattern_type {
     ($($arg:tt)*) => {
         /* compiler built-in */
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 585946c1d50e0..6be27b283b291 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -589,7 +589,7 @@ pub mod net;
 pub mod num;
 pub mod os;
 pub mod panic;
-#[unstable(feature = "core_pattern_types", issue = "123646")]
+#[unstable(feature = "pattern_type_macro", issue = "123646")]
 pub mod pat;
 pub mod path;
 #[unstable(feature = "anonymous_pipe", issue = "127154")]
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
index 266109765ab8c..b97dfb3b8ef8b 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
@@ -3936,17 +3936,8 @@ The tracking issue for this feature is: [#117693]
 "##,
     },
     Lint {
-        label: "core_pattern_type",
-        description: r##"# `core_pattern_type`
-
-This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.
-
-------------------------
-"##,
-    },
-    Lint {
-        label: "core_pattern_types",
-        description: r##"# `core_pattern_types`
+        label: "pattern_type_macro",
+        description: r##"# `pattern_type_macro`
 
 This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.
 
diff --git a/tests/codegen/pattern_type_symbols.rs b/tests/codegen/pattern_type_symbols.rs
index a99b3efca415b..b504a3508f94c 100644
--- a/tests/codegen/pattern_type_symbols.rs
+++ b/tests/codegen/pattern_type_symbols.rs
@@ -4,8 +4,7 @@
 //@ compile-flags: -Csymbol-mangling-version=v0 -Copt-level=0 --crate-type=lib
 
 #![feature(pattern_types)]
-#![feature(core_pattern_types)]
-#![feature(core_pattern_type)]
+#![feature(pattern_type_macro)]
 
 use std::pat::pattern_type;
 
diff --git a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs
index 3defe0cb44d3b..55f45ade38804 100644
--- a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs
+++ b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs
@@ -1,4 +1,4 @@
-#![feature(pattern_types, core_pattern_type)]
+#![feature(pattern_types, pattern_type_macro)]
 #![allow(internal_features)]
 
 type Pat<const START: u32, const END: u32> =
diff --git a/tests/ui/type/pattern_types/bad_pat.rs b/tests/ui/type/pattern_types/bad_pat.rs
index 8ad042eeba65e..6cb2a0f1f8e74 100644
--- a/tests/ui/type/pattern_types/bad_pat.rs
+++ b/tests/ui/type/pattern_types/bad_pat.rs
@@ -1,6 +1,5 @@
 #![feature(pattern_types)]
-#![feature(core_pattern_types)]
-#![feature(core_pattern_type)]
+#![feature(pattern_type_macro)]
 
 use std::pat::pattern_type;
 
diff --git a/tests/ui/type/pattern_types/bad_pat.stderr b/tests/ui/type/pattern_types/bad_pat.stderr
index f5cf7930c8328..c857cc3c3add9 100644
--- a/tests/ui/type/pattern_types/bad_pat.stderr
+++ b/tests/ui/type/pattern_types/bad_pat.stderr
@@ -1,5 +1,5 @@
 error[E0586]: inclusive range with no end
-  --> $DIR/bad_pat.rs:7:43
+  --> $DIR/bad_pat.rs:6:43
    |
 LL | type NonNullU32_2 = pattern_type!(u32 is 1..=);
    |                                           ^^^
@@ -12,7 +12,7 @@ LL + type NonNullU32_2 = pattern_type!(u32 is 1..);
    |
 
 error[E0586]: inclusive range with no end
-  --> $DIR/bad_pat.rs:9:40
+  --> $DIR/bad_pat.rs:8:40
    |
 LL | type Positive2 = pattern_type!(i32 is 0..=);
    |                                        ^^^
@@ -25,7 +25,7 @@ LL + type Positive2 = pattern_type!(i32 is 0..);
    |
 
 error: wildcard patterns are not permitted for pattern types
-  --> $DIR/bad_pat.rs:11:33
+  --> $DIR/bad_pat.rs:10:33
    |
 LL | type Wild = pattern_type!(() is _);
    |                                 ^
diff --git a/tests/ui/type/pattern_types/const_generics.rs b/tests/ui/type/pattern_types/const_generics.rs
index 5bc6fd54e0fce..5cef0dc030552 100644
--- a/tests/ui/type/pattern_types/const_generics.rs
+++ b/tests/ui/type/pattern_types/const_generics.rs
@@ -1,8 +1,7 @@
 //@ check-pass
 
 #![feature(pattern_types)]
-#![feature(core_pattern_types)]
-#![feature(core_pattern_type)]
+#![feature(pattern_type_macro)]
 
 use std::pat::pattern_type;
 
diff --git a/tests/ui/type/pattern_types/derives.rs b/tests/ui/type/pattern_types/derives.rs
index b8b53e61102bc..3878c47554d98 100644
--- a/tests/ui/type/pattern_types/derives.rs
+++ b/tests/ui/type/pattern_types/derives.rs
@@ -1,8 +1,7 @@
 //! Check that pattern types don't implement traits of their base automatically
 
 #![feature(pattern_types)]
-#![feature(core_pattern_types)]
-#![feature(core_pattern_type)]
+#![feature(pattern_type_macro)]
 
 use std::pat::pattern_type;
 
diff --git a/tests/ui/type/pattern_types/derives.stderr b/tests/ui/type/pattern_types/derives.stderr
index 1d4d3fc55c3fa..9d4baef621be3 100644
--- a/tests/ui/type/pattern_types/derives.stderr
+++ b/tests/ui/type/pattern_types/derives.stderr
@@ -1,5 +1,5 @@
 error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
-  --> $DIR/derives.rs:11:20
+  --> $DIR/derives.rs:10:20
    |
 LL | #[derive(Clone, Copy, PartialEq)]
    |                       --------- in this derive macro expansion
diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types.rs b/tests/ui/type/pattern_types/feature-gate-pattern_types.rs
index e638f3c6c40d7..b90ba4784023a 100644
--- a/tests/ui/type/pattern_types/feature-gate-pattern_types.rs
+++ b/tests/ui/type/pattern_types/feature-gate-pattern_types.rs
@@ -3,12 +3,12 @@
 use std::pat::pattern_type;
 
 type NonNullU32 = pattern_type!(u32 is 1..);
-//~^ use of unstable library feature `core_pattern_type`
+//~^ use of unstable library feature `pattern_type_macro`
 type Percent = pattern_type!(u32 is 0..=100);
-//~^ use of unstable library feature `core_pattern_type`
+//~^ use of unstable library feature `pattern_type_macro`
 type Negative = pattern_type!(i32 is ..=0);
-//~^ use of unstable library feature `core_pattern_type`
+//~^ use of unstable library feature `pattern_type_macro`
 type Positive = pattern_type!(i32 is 0..);
-//~^ use of unstable library feature `core_pattern_type`
+//~^ use of unstable library feature `pattern_type_macro`
 type Always = pattern_type!(Option<u32> is Some(_));
-//~^ use of unstable library feature `core_pattern_type`
+//~^ use of unstable library feature `pattern_type_macro`
diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr b/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr
index 6cbadf370a7dc..69239d68bdc75 100644
--- a/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr
+++ b/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr
@@ -1,51 +1,51 @@
-error[E0658]: use of unstable library feature `core_pattern_type`
+error[E0658]: use of unstable library feature `pattern_type_macro`
   --> $DIR/feature-gate-pattern_types.rs:5:19
    |
 LL | type NonNullU32 = pattern_type!(u32 is 1..);
    |                   ^^^^^^^^^^^^
    |
    = note: see issue #123646 <https://github.com/rust-lang/rust/issues/123646> for more information
-   = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
+   = help: add `#![feature(pattern_type_macro)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: use of unstable library feature `core_pattern_type`
+error[E0658]: use of unstable library feature `pattern_type_macro`
   --> $DIR/feature-gate-pattern_types.rs:7:16
    |
 LL | type Percent = pattern_type!(u32 is 0..=100);
    |                ^^^^^^^^^^^^
    |
    = note: see issue #123646 <https://github.com/rust-lang/rust/issues/123646> for more information
-   = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
+   = help: add `#![feature(pattern_type_macro)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: use of unstable library feature `core_pattern_type`
+error[E0658]: use of unstable library feature `pattern_type_macro`
   --> $DIR/feature-gate-pattern_types.rs:9:17
    |
 LL | type Negative = pattern_type!(i32 is ..=0);
    |                 ^^^^^^^^^^^^
    |
    = note: see issue #123646 <https://github.com/rust-lang/rust/issues/123646> for more information
-   = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
+   = help: add `#![feature(pattern_type_macro)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: use of unstable library feature `core_pattern_type`
+error[E0658]: use of unstable library feature `pattern_type_macro`
   --> $DIR/feature-gate-pattern_types.rs:11:17
    |
 LL | type Positive = pattern_type!(i32 is 0..);
    |                 ^^^^^^^^^^^^
    |
    = note: see issue #123646 <https://github.com/rust-lang/rust/issues/123646> for more information
-   = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
+   = help: add `#![feature(pattern_type_macro)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: use of unstable library feature `core_pattern_type`
+error[E0658]: use of unstable library feature `pattern_type_macro`
   --> $DIR/feature-gate-pattern_types.rs:13:15
    |
 LL | type Always = pattern_type!(Option<u32> is Some(_));
    |               ^^^^^^^^^^^^
    |
    = note: see issue #123646 <https://github.com/rust-lang/rust/issues/123646> for more information
-   = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
+   = help: add `#![feature(pattern_type_macro)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: aborting due to 5 previous errors
diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs b/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs
index d7b3ea58e0265..50c355c8de61a 100644
--- a/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs
+++ b/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs
@@ -1,7 +1,7 @@
 //@ compile-flags: -Zno-analysis
 //@ check-pass
 
-#![feature(core_pattern_type)]
+#![feature(pattern_type_macro)]
 
 use std::pat::pattern_type;
 
diff --git a/tests/ui/type/pattern_types/missing-is.rs b/tests/ui/type/pattern_types/missing-is.rs
index 2fbcc1908efcb..564b41649d899 100644
--- a/tests/ui/type/pattern_types/missing-is.rs
+++ b/tests/ui/type/pattern_types/missing-is.rs
@@ -1,4 +1,4 @@
-#![feature(core_pattern_type, core_pattern_types)]
+#![feature(pattern_type_macro)]
 
 use std::pat::pattern_type;
 
diff --git a/tests/ui/type/pattern_types/range_patterns.rs b/tests/ui/type/pattern_types/range_patterns.rs
index 9eddc8cab7fe1..7c25edb1c3fd5 100644
--- a/tests/ui/type/pattern_types/range_patterns.rs
+++ b/tests/ui/type/pattern_types/range_patterns.rs
@@ -1,6 +1,5 @@
 #![feature(pattern_types, rustc_attrs)]
-#![feature(core_pattern_type)]
-#![feature(core_pattern_types)]
+#![feature(pattern_type_macro)]
 #![allow(incomplete_features)]
 
 //@ normalize-stderr-test: "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN"
diff --git a/tests/ui/type/pattern_types/range_patterns.stderr b/tests/ui/type/pattern_types/range_patterns.stderr
index 7bd0d826cab71..0eed7c2ce1ce8 100644
--- a/tests/ui/type/pattern_types/range_patterns.stderr
+++ b/tests/ui/type/pattern_types/range_patterns.stderr
@@ -37,7 +37,7 @@ error: layout_of(NonZero<u32>) = Layout {
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
        }
-  --> $DIR/range_patterns.rs:11:1
+  --> $DIR/range_patterns.rs:10:1
    |
 LL | type X = std::num::NonZeroU32;
    | ^^^^^^
@@ -74,7 +74,7 @@ error: layout_of((u32) is 1..=) = Layout {
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
        }
-  --> $DIR/range_patterns.rs:13:1
+  --> $DIR/range_patterns.rs:12:1
    |
 LL | type Y = pattern_type!(u32 is 1..);
    | ^^^^^^
@@ -182,7 +182,7 @@ error: layout_of(Option<(u32) is 1..=>) = Layout {
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
        }
-  --> $DIR/range_patterns.rs:15:1
+  --> $DIR/range_patterns.rs:14:1
    |
 LL | type Z = Option<pattern_type!(u32 is 1..)>;
    | ^^^^^^
@@ -290,7 +290,7 @@ error: layout_of(Option<NonZero<u32>>) = Layout {
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
        }
-  --> $DIR/range_patterns.rs:17:1
+  --> $DIR/range_patterns.rs:16:1
    |
 LL | type A = Option<std::num::NonZeroU32>;
    | ^^^^^^
@@ -334,7 +334,7 @@ error: layout_of(NonZeroU32New) = Layout {
            max_repr_align: None,
            unadjusted_abi_align: Align(4 bytes),
        }
-  --> $DIR/range_patterns.rs:19:1
+  --> $DIR/range_patterns.rs:18:1
    |
 LL | struct NonZeroU32New(pattern_type!(u32 is 1..));
    | ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/type/pattern_types/range_patterns_inherent_impls.rs b/tests/ui/type/pattern_types/range_patterns_inherent_impls.rs
index 9653a744c4162..fe8feda0934e2 100644
--- a/tests/ui/type/pattern_types/range_patterns_inherent_impls.rs
+++ b/tests/ui/type/pattern_types/range_patterns_inherent_impls.rs
@@ -1,6 +1,5 @@
 #![feature(pattern_types, rustc_attrs)]
-#![feature(core_pattern_type)]
-#![feature(core_pattern_types)]
+#![feature(pattern_type_macro)]
 #![allow(incomplete_features)]
 
 //! check that pattern types can have traits implemented for them if
diff --git a/tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr b/tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr
index 784ebb0c9f012..ed2e4c0bd5f8c 100644
--- a/tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr
+++ b/tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr
@@ -1,12 +1,12 @@
 error[E0390]: cannot define inherent `impl` for primitive types outside of `core`
-  --> $DIR/range_patterns_inherent_impls.rs:13:1
+  --> $DIR/range_patterns_inherent_impls.rs:12:1
    |
 LL | impl Y {
    | ^^^^^^
    |
    = help: consider moving this inherent impl into `core` if possible
 help: alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
-  --> $DIR/range_patterns_inherent_impls.rs:15:5
+  --> $DIR/range_patterns_inherent_impls.rs:14:5
    |
 LL |     fn foo() {}
    |     ^^^^^^^^
diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls.rs b/tests/ui/type/pattern_types/range_patterns_trait_impls.rs
index f8c9af8628182..1731cd470fe2c 100644
--- a/tests/ui/type/pattern_types/range_patterns_trait_impls.rs
+++ b/tests/ui/type/pattern_types/range_patterns_trait_impls.rs
@@ -1,6 +1,5 @@
 #![feature(pattern_types, rustc_attrs)]
-#![feature(core_pattern_type)]
-#![feature(core_pattern_types)]
+#![feature(pattern_type_macro)]
 #![allow(incomplete_features)]
 
 //! check that pattern types can have local traits
diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls2.rs b/tests/ui/type/pattern_types/range_patterns_trait_impls2.rs
index acde4580c1b20..90f80a2f34645 100644
--- a/tests/ui/type/pattern_types/range_patterns_trait_impls2.rs
+++ b/tests/ui/type/pattern_types/range_patterns_trait_impls2.rs
@@ -1,6 +1,5 @@
 #![feature(pattern_types, rustc_attrs)]
-#![feature(core_pattern_type)]
-#![feature(core_pattern_types)]
+#![feature(pattern_type_macro)]
 #![allow(incomplete_features)]
 
 //! check that pattern types can have local traits
diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr b/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr
index df56db031ed18..d5c539b6c52e6 100644
--- a/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr
+++ b/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr
@@ -1,5 +1,5 @@
 error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
-  --> $DIR/range_patterns_trait_impls2.rs:13:1
+  --> $DIR/range_patterns_trait_impls2.rs:12:1
    |
 LL | impl Eq for Y {}
    | ^^^^^^^^^^^^-
diff --git a/tests/ui/type/pattern_types/range_patterns_unusable.rs b/tests/ui/type/pattern_types/range_patterns_unusable.rs
index 7cde44f41335b..98f13ca0bc0bb 100644
--- a/tests/ui/type/pattern_types/range_patterns_unusable.rs
+++ b/tests/ui/type/pattern_types/range_patterns_unusable.rs
@@ -1,6 +1,5 @@
 #![feature(pattern_types, rustc_attrs)]
-#![feature(core_pattern_type)]
-#![feature(core_pattern_types)]
+#![feature(pattern_type_macro)]
 #![allow(incomplete_features)]
 
 //! Some practical niche checks.
diff --git a/tests/ui/type/pattern_types/range_patterns_unusable.stderr b/tests/ui/type/pattern_types/range_patterns_unusable.stderr
index aa0e592684b6b..8377d417452bb 100644
--- a/tests/ui/type/pattern_types/range_patterns_unusable.stderr
+++ b/tests/ui/type/pattern_types/range_patterns_unusable.stderr
@@ -1,5 +1,5 @@
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
-  --> $DIR/range_patterns_unusable.rs:14:35
+  --> $DIR/range_patterns_unusable.rs:13:35
    |
 LL |     let _: Option<u32> = unsafe { std::mem::transmute(z) };
    |                                   ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/type/pattern_types/range_patterns_unusable_math.rs b/tests/ui/type/pattern_types/range_patterns_unusable_math.rs
index bc1ab75429d66..ece4009e1e7d8 100644
--- a/tests/ui/type/pattern_types/range_patterns_unusable_math.rs
+++ b/tests/ui/type/pattern_types/range_patterns_unusable_math.rs
@@ -1,6 +1,5 @@
 #![feature(pattern_types, rustc_attrs)]
-#![feature(core_pattern_type)]
-#![feature(core_pattern_types)]
+#![feature(pattern_type_macro)]
 #![allow(incomplete_features)]
 
 //! check that pattern types don't have an `Add` impl.
diff --git a/tests/ui/type/pattern_types/range_patterns_unusable_math.stderr b/tests/ui/type/pattern_types/range_patterns_unusable_math.stderr
index e52d899a703f2..373615e3714e5 100644
--- a/tests/ui/type/pattern_types/range_patterns_unusable_math.stderr
+++ b/tests/ui/type/pattern_types/range_patterns_unusable_math.stderr
@@ -1,5 +1,5 @@
 error[E0369]: cannot add `u32` to `(u32) is 1..=`
-  --> $DIR/range_patterns_unusable_math.rs:15:15
+  --> $DIR/range_patterns_unusable_math.rs:14:15
    |
 LL |     let x = x + 1_u32;
    |             - ^ ----- u32
diff --git a/tests/ui/type/pattern_types/range_patterns_usage.rs b/tests/ui/type/pattern_types/range_patterns_usage.rs
index 2a9f736ae61d5..0ecbdcaa0f7a3 100644
--- a/tests/ui/type/pattern_types/range_patterns_usage.rs
+++ b/tests/ui/type/pattern_types/range_patterns_usage.rs
@@ -1,6 +1,5 @@
 #![feature(pattern_types, rustc_attrs)]
-#![feature(core_pattern_type)]
-#![feature(core_pattern_types)]
+#![feature(pattern_type_macro)]
 #![allow(incomplete_features)]
 //@ check-pass
 
diff --git a/tests/ui/type/pattern_types/unimplemented_pat.rs b/tests/ui/type/pattern_types/unimplemented_pat.rs
index c02160ff58a6c..b2398cec7c9b5 100644
--- a/tests/ui/type/pattern_types/unimplemented_pat.rs
+++ b/tests/ui/type/pattern_types/unimplemented_pat.rs
@@ -1,8 +1,7 @@
 //! This test ensures we do not ICE for unimplemented
 //! patterns unless the feature gate is enabled.
 
-#![feature(core_pattern_type)]
-#![feature(core_pattern_types)]
+#![feature(pattern_type_macro)]
 
 use std::pat::pattern_type;
 
diff --git a/tests/ui/type/pattern_types/unimplemented_pat.stderr b/tests/ui/type/pattern_types/unimplemented_pat.stderr
index 481c6017dccc2..7b0f9cbaa6a96 100644
--- a/tests/ui/type/pattern_types/unimplemented_pat.stderr
+++ b/tests/ui/type/pattern_types/unimplemented_pat.stderr
@@ -1,5 +1,5 @@
 error[E0658]: pattern types are unstable
-  --> $DIR/unimplemented_pat.rs:9:15
+  --> $DIR/unimplemented_pat.rs:8:15
    |
 LL | type Always = pattern_type!(Option<u32> is Some(_));
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL | type Always = pattern_type!(Option<u32> is Some(_));
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: pattern types are unstable
-  --> $DIR/unimplemented_pat.rs:12:16
+  --> $DIR/unimplemented_pat.rs:11:16
    |
 LL | type Binding = pattern_type!(Option<u32> is x);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs
index 891021e876609..9af57fe4c3cd0 100644
--- a/tests/ui/unpretty/expanded-exhaustive.rs
+++ b/tests/ui/unpretty/expanded-exhaustive.rs
@@ -8,7 +8,6 @@
 #![feature(builtin_syntax)]
 #![feature(concat_idents)]
 #![feature(const_trait_impl)]
-#![feature(core_pattern_type)]
 #![feature(decl_macro)]
 #![feature(deref_patterns)]
 #![feature(explicit_tail_calls)]
@@ -18,6 +17,7 @@
 #![feature(never_patterns)]
 #![feature(never_type)]
 #![feature(pattern_types)]
+#![feature(pattern_type_macro)]
 #![feature(prelude_import)]
 #![feature(specialization)]
 #![feature(trace_macros)]
diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout
index 007626e2c4406..14a274415ca72 100644
--- a/tests/ui/unpretty/expanded-exhaustive.stdout
+++ b/tests/ui/unpretty/expanded-exhaustive.stdout
@@ -9,7 +9,6 @@
 #![feature(builtin_syntax)]
 #![feature(concat_idents)]
 #![feature(const_trait_impl)]
-#![feature(core_pattern_type)]
 #![feature(decl_macro)]
 #![feature(deref_patterns)]
 #![feature(explicit_tail_calls)]
@@ -19,6 +18,7 @@
 #![feature(never_patterns)]
 #![feature(never_type)]
 #![feature(pattern_types)]
+#![feature(pattern_type_macro)]
 #![feature(prelude_import)]
 #![feature(specialization)]
 #![feature(trace_macros)]

From 1b449e123d8d935b3ac7d475e3fc075860af444e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 4 Dec 2024 05:57:55 +0000
Subject: [PATCH 06/21] Do not emit empty suggestion

The `println!();` statement's span doesn't include the `;`, and the modified suggestions where trying to get the `;` by getting the differenece between the statement's and the expression's spans, which was an empty suggestion.

Fix #133833, fix #133834.
---
 .../src/fn_ctxt/suggestions.rs                |  8 ++-
 .../src/error_reporting/traits/suggestions.rs |  6 +++
 ...uggestion-when-stmt-and-expr-span-equal.rs | 26 ++++++++++
 ...stion-when-stmt-and-expr-span-equal.stderr | 50 +++++++++++++++++++
 4 files changed, 89 insertions(+), 1 deletion(-)
 create mode 100644 tests/ui/suggestions/semi-suggestion-when-stmt-and-expr-span-equal.rs
 create mode 100644 tests/ui/suggestions/semi-suggestion-when-stmt-and-expr-span-equal.stderr

diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 61260dbd16c51..ddcd90a2a9da6 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -3394,7 +3394,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let Some(ty) = self.node_ty_opt(tail_expr.hir_id) else {
             return;
         };
-        if self.can_eq(self.param_env, expected_ty, ty) {
+        if self.can_eq(self.param_env, expected_ty, ty)
+            // FIXME: this happens with macro calls. Need to figure out why the stmt
+            // `println!();` doesn't include the `;` in its `Span`. (#133845)
+            // We filter these out to avoid ICEs with debug assertions on caused by
+            // empty suggestions.
+            && stmt.span.hi() != tail_expr.span.hi()
+        {
             err.span_suggestion_short(
                 stmt.span.with_lo(tail_expr.span.hi()),
                 "remove this semicolon",
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 2bb503f17b4ed..94682f501a8c4 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -3838,6 +3838,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 && self.predicate_must_hold_modulo_regions(&Obligation::misc(
                     tcx, expr.span, body_id, param_env, pred,
                 ))
+                && expr.span.hi() != rcvr.span.hi()
             {
                 err.span_suggestion_verbose(
                     expr.span.with_lo(rcvr.span.hi()),
@@ -4115,6 +4116,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         // the expected is a projection that we need to resolve.
                         // && let Some(tail_ty) = typeck_results.expr_ty_opt(expr)
                         && expected_found.found.is_unit()
+                        // FIXME: this happens with macro calls. Need to figure out why the stmt
+                        // `println!();` doesn't include the `;` in its `Span`. (#133845)
+                        // We filter these out to avoid ICEs with debug assertions on caused by
+                        // empty suggestions.
+                        && expr.span.hi() != stmt.span.hi()
                     {
                         err.span_suggestion_verbose(
                             expr.span.shrink_to_hi().with_hi(stmt.span.hi()),
diff --git a/tests/ui/suggestions/semi-suggestion-when-stmt-and-expr-span-equal.rs b/tests/ui/suggestions/semi-suggestion-when-stmt-and-expr-span-equal.rs
new file mode 100644
index 0000000000000..35612093aff04
--- /dev/null
+++ b/tests/ui/suggestions/semi-suggestion-when-stmt-and-expr-span-equal.rs
@@ -0,0 +1,26 @@
+//! Regression test for suggestions that were fired on empty spans
+//! involving macro-call statements. For some reason the semicolon
+//! is not included in the overall span of the macro-call statement.
+//!
+//! Issue 1: <https://github.com/rust-lang/rust/issues/133833>.
+//! Issue 2: <https://github.com/rust-lang/rust/issues/133834>.
+//! See also: <https://github.com/rust-lang/rust/issues/133845>.
+
+fn foo() -> String {
+    let mut list = {
+        println!();
+    };
+    list //~ ERROR mismatched types
+}
+
+fn bar() {
+    String::new()
+        .chars()
+        .filter(|x| !x.is_whitespace())
+        .map(|x| {
+            println!("Child spawned with the size: {}", x);
+        })
+        .collect::<String>(); //~ ERROR E0277
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/semi-suggestion-when-stmt-and-expr-span-equal.stderr b/tests/ui/suggestions/semi-suggestion-when-stmt-and-expr-span-equal.stderr
new file mode 100644
index 0000000000000..4b83bfff86333
--- /dev/null
+++ b/tests/ui/suggestions/semi-suggestion-when-stmt-and-expr-span-equal.stderr
@@ -0,0 +1,50 @@
+error[E0308]: mismatched types
+  --> $DIR/semi-suggestion-when-stmt-and-expr-span-equal.rs:13:5
+   |
+LL |   fn foo() -> String {
+   |               ------ expected `String` because of return type
+LL |       let mut list = {
+   |  ____________________-
+LL | |         println!();
+LL | |     };
+   | |_____- this block is missing a tail expression
+LL |       list
+   |       ^^^^ expected `String`, found `()`
+
+error[E0277]: a value of type `String` cannot be built from an iterator over elements of type `()`
+  --> $DIR/semi-suggestion-when-stmt-and-expr-span-equal.rs:23:20
+   |
+LL |         .collect::<String>();
+   |          -------   ^^^^^^ value of type `String` cannot be built from `std::iter::Iterator<Item=()>`
+   |          |
+   |          required by a bound introduced by this call
+   |
+   = help: the trait `FromIterator<()>` is not implemented for `String`
+   = help: the following other types implement trait `FromIterator<A>`:
+             `String` implements `FromIterator<&char>`
+             `String` implements `FromIterator<&str>`
+             `String` implements `FromIterator<Box<str, A>>`
+             `String` implements `FromIterator<Cow<'_, str>>`
+             `String` implements `FromIterator<String>`
+             `String` implements `FromIterator<char>`
+note: the method call chain might not have had the expected associated types
+  --> $DIR/semi-suggestion-when-stmt-and-expr-span-equal.rs:20:10
+   |
+LL |       String::new()
+   |       ------------- this expression has type `String`
+LL |           .chars()
+   |            ------- `Iterator::Item` is `char` here
+LL |           .filter(|x| !x.is_whitespace())
+   |            ------------------------------ `Iterator::Item` remains `char` here
+LL |           .map(|x| {
+   |  __________^
+LL | |             println!("Child spawned with the size: {}", x);
+LL | |         })
+   | |__________^ `Iterator::Item` changed to `()` here
+note: required by a bound in `collect`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.

From 05c34cc5ed35dbf32f83e2eaa0ebbda4c4953294 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Fri, 8 Mar 2024 00:02:11 +0000
Subject: [PATCH 07/21] Fix suggestion when shorthand self has erroneous type

---
 compiler/rustc_ast/src/ast.rs           | 12 ++++++
 compiler/rustc_parse/messages.ftl       |  3 ++
 compiler/rustc_parse/src/errors.rs      | 19 ++++++++++
 compiler/rustc_parse/src/parser/item.rs | 30 ++++++++++++++-
 tests/ui/parser/typed-self-param.rs     | 14 +++++++
 tests/ui/parser/typed-self-param.stderr | 50 +++++++++++++++++++++++++
 6 files changed, 127 insertions(+), 1 deletion(-)
 create mode 100644 tests/ui/parser/typed-self-param.rs
 create mode 100644 tests/ui/parser/typed-self-param.stderr

diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index ed2a3a507c8ab..2f55a9eaedab3 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2566,6 +2566,18 @@ pub enum SelfKind {
     Explicit(P<Ty>, Mutability),
 }
 
+impl SelfKind {
+    pub fn to_ref_suggestion(&self) -> String {
+        match self {
+            SelfKind::Region(None, mutbl) => mutbl.ref_prefix_str().to_string(),
+            SelfKind::Region(Some(lt), mutbl) => format!("&{lt} {}", mutbl.prefix_str()),
+            SelfKind::Value(_) | SelfKind::Explicit(_, _) => {
+                unreachable!("if we had an explicit self, we wouldn't be here")
+            }
+        }
+    }
+}
+
 pub type ExplicitSelf = Spanned<SelfKind>;
 
 impl Param {
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index b9a325eddd800..e5cd4622dae90 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -343,6 +343,9 @@ parse_incorrect_semicolon =
     .suggestion = remove this semicolon
     .help = {$name} declarations are not followed by a semicolon
 
+parse_incorrect_type_on_self = type not allowed for shorthand `self` parameter
+    .suggestion = move the modifiers on `self` to the type
+
 parse_incorrect_use_of_await = incorrect use of `await`
     .parentheses_suggestion = `await` is not a method call, remove the parentheses
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 2579e4c1f2596..14f2dd32e9232 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -3409,3 +3409,22 @@ pub(crate) struct PolarityAndModifiers {
     pub polarity: &'static str,
     pub modifiers_concatenated: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(parse_incorrect_type_on_self)]
+pub(crate) struct IncorrectTypeOnSelf {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub move_self_modifier: MoveSelfModifier,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
+pub(crate) struct MoveSelfModifier {
+    #[suggestion_part(code = "")]
+    pub removal_span: Span,
+    #[suggestion_part(code = "{modifier}")]
+    pub insertion_span: Span,
+    pub modifier: String,
+}
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 26e81b7676bb1..475cd09147f5c 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -2941,6 +2941,32 @@ impl<'a> Parser<'a> {
             };
             Ok((eself, eself_ident, eself_hi))
         };
+        let expect_self_ident_not_typed =
+            |this: &mut Self, modifier: &SelfKind, modifier_span: Span| {
+                let eself_ident = expect_self_ident(this);
+
+                // Recover `: Type` after a qualified self
+                if this.may_recover() && this.eat_noexpect(&token::Colon) {
+                    let snap = this.create_snapshot_for_diagnostic();
+                    match this.parse_ty() {
+                        Ok(ty) => {
+                            this.dcx().emit_err(errors::IncorrectTypeOnSelf {
+                                span: ty.span,
+                                move_self_modifier: errors::MoveSelfModifier {
+                                    removal_span: modifier_span,
+                                    insertion_span: ty.span.shrink_to_lo(),
+                                    modifier: modifier.to_ref_suggestion(),
+                                },
+                            });
+                        }
+                        Err(diag) => {
+                            diag.cancel();
+                            this.restore_snapshot(snap);
+                        }
+                    }
+                }
+                eself_ident
+            };
         // Recover for the grammar `*self`, `*const self`, and `*mut self`.
         let recover_self_ptr = |this: &mut Self| {
             this.dcx().emit_err(errors::SelfArgumentPointer { span: this.token.span });
@@ -2978,7 +3004,9 @@ impl<'a> Parser<'a> {
                     // `&not_self`
                     return Ok(None);
                 };
-                (eself, expect_self_ident(self), self.prev_token.span)
+                let hi = self.token.span;
+                let self_ident = expect_self_ident_not_typed(self, &eself, eself_lo.until(hi));
+                (eself, self_ident, hi)
             }
             // `*self`
             token::BinOp(token::Star) if is_isolated_self(self, 1) => {
diff --git a/tests/ui/parser/typed-self-param.rs b/tests/ui/parser/typed-self-param.rs
new file mode 100644
index 0000000000000..e3d85ab891b5b
--- /dev/null
+++ b/tests/ui/parser/typed-self-param.rs
@@ -0,0 +1,14 @@
+struct S;
+
+impl S {
+    fn a(&self: Self) {}
+    //~^ ERROR type not allowed for shorthand `self` parameter
+    fn b(&mut self: Self) {}
+    //~^ ERROR type not allowed for shorthand `self` parameter
+    fn c<'c>(&'c mut self: Self) {}
+    //~^ ERROR type not allowed for shorthand `self` parameter
+    fn d<'d>(&'d self: Self) {}
+    //~^ ERROR type not allowed for shorthand `self` parameter
+}
+
+fn main() {}
diff --git a/tests/ui/parser/typed-self-param.stderr b/tests/ui/parser/typed-self-param.stderr
new file mode 100644
index 0000000000000..c1ecd3b7fef43
--- /dev/null
+++ b/tests/ui/parser/typed-self-param.stderr
@@ -0,0 +1,50 @@
+error: type not allowed for shorthand `self` parameter
+  --> $DIR/typed-self-param.rs:4:17
+   |
+LL |     fn a(&self: Self) {}
+   |                 ^^^^
+   |
+help: move the modifiers on `self` to the type
+   |
+LL -     fn a(&self: Self) {}
+LL +     fn a(self: &Self) {}
+   |
+
+error: type not allowed for shorthand `self` parameter
+  --> $DIR/typed-self-param.rs:6:21
+   |
+LL |     fn b(&mut self: Self) {}
+   |                     ^^^^
+   |
+help: move the modifiers on `self` to the type
+   |
+LL -     fn b(&mut self: Self) {}
+LL +     fn b(self: &mut Self) {}
+   |
+
+error: type not allowed for shorthand `self` parameter
+  --> $DIR/typed-self-param.rs:8:28
+   |
+LL |     fn c<'c>(&'c mut self: Self) {}
+   |                            ^^^^
+   |
+help: move the modifiers on `self` to the type
+   |
+LL -     fn c<'c>(&'c mut self: Self) {}
+LL +     fn c<'c>(self: &'c mut Self) {}
+   |
+
+error: type not allowed for shorthand `self` parameter
+  --> $DIR/typed-self-param.rs:10:24
+   |
+LL |     fn d<'d>(&'d self: Self) {}
+   |                        ^^^^
+   |
+help: move the modifiers on `self` to the type
+   |
+LL -     fn d<'d>(&'d self: Self) {}
+LL +     fn d<'d>(self: &'d Self) {}
+   |
+
+error: aborting due to 4 previous errors
+

From c6205055e085a1210c1503978225d34147a0d8bd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 20 Nov 2024 02:15:21 +0000
Subject: [PATCH 08/21] On `const` pattern errors, point at the `const` item
 definition

Centralize emitting an error in `const_to_pat` so that all errors from that evaluating a `const` in a pattern can add addditional information. With this, now point at the `const` item's definition:

```
error[E0158]: constant pattern depends on a generic parameter
  --> $DIR/associated-const-type-parameter-pattern.rs:20:9
   |
LL | pub trait Foo {
   | -------------
LL |     const X: EFoo;
   |     ------------- constant defined here
...
LL |         A::X => println!("A::X"),
   |         ^^^^
```
---
 compiler/rustc_mir_build/messages.ftl         |   2 +
 .../src/thir/pattern/const_to_pat.rs          | 103 ++++++++++++------
 ...ciated-const-type-parameter-pattern.stderr |  20 ++++
 ...e-type-mismatch-when-copying-112824.stderr |   5 +
 .../const-eval/const-eval-overflow-2.stderr   |   3 +
 .../const-eval/ref_to_int_match.64bit.stderr  |   3 +
 .../const_in_pattern/cross-crate-fail.stderr  |  10 ++
 ...ssue-34784-match-on-non-int-raw-ptr.stderr |  12 ++
 .../const_in_pattern/issue-44333.stderr       |   6 +
 .../const_in_pattern/issue-65466.stderr       |   3 +
 .../const_in_pattern/no-eq-branch-fail.stderr |   3 +
 .../reject_non_partial_eq.stderr              |   3 +
 .../const_in_pattern/reject_non_structural.rs |  20 ++--
 .../reject_non_structural.stderr              |  21 ++++
 .../const_refs_to_static_fail_invalid.stderr  |   9 ++
 tests/ui/consts/issue-43105.stderr            |   3 +
 .../ui/consts/issue-73976-polymorphic.stderr  |  10 ++
 tests/ui/consts/issue-78655.stderr            |   3 +
 tests/ui/consts/issue-79137-toogeneric.stderr |   5 +
 tests/ui/consts/issue-87046.stderr            |   3 +
 tests/ui/consts/issue-89088.stderr            |   3 +
 tests/ui/consts/match_ice.stderr              |   3 +
 .../const_refers_to_static_cross_crate.stderr |  12 ++
 .../ui/consts/missing_assoc_const_type.stderr |   5 +
 ...ansmute-size-mismatch-before-typeck.stderr |   3 +
 tests/ui/match/issue-70972-dyn-trait.stderr   |   3 +
 .../issue-72896-non-partial-eq-const.stderr   |   3 +
 tests/ui/pattern/issue-115599.stderr          |   3 +
 tests/ui/pattern/issue-72565.stderr           |   3 +
 .../const-partial_eq-fallback-ice.stderr      |   3 +
 .../pattern/usefulness/consts-opaque.stderr   |  24 ++++
 ...-hide-behind-direct-struct-embedded.stderr |   3 +
 ...ant-hide-behind-direct-struct-param.stderr |   3 +
 ...ide-behind-doubly-indirect-embedded.stderr |   3 +
 ...t-hide-behind-doubly-indirect-param.stderr |   3 +
 ...ide-behind-indirect-struct-embedded.stderr |   3 +
 ...t-hide-behind-indirect-struct-param.stderr |   3 +
 ...n-ptr-is-not-structurally-matchable.stderr |  30 +++++
 ...88-match-slice-forbidden-without-eq.stderr |   3 +
 ...-match-ref-ref-forbidden-without-eq.stderr |   6 +
 .../issue-63479-match-fnptr.stderr            |   6 +
 .../issue-6804-nan-match.stderr               |  21 ++++
 ...atch-requires-both-partialeq-and-eq.stderr |   3 +
 .../structural-match-no-leak.stderr           |   3 +
 .../structural-match.stderr                   |   3 +
 tests/ui/union/union-const-pat.stderr         |   3 +
 46 files changed, 365 insertions(+), 43 deletions(-)

diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index f28cf84fa693e..fdefc0bfd190c 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -84,6 +84,8 @@ mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
 
 mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable
 
+mir_build_const_defined_here = constant defined here
+
 mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns
 
 mir_build_const_pattern_depends_on_generic_parameter =
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 5db08f01fdbdc..aa98874654edd 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,5 +1,6 @@
 use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_apfloat::Float;
+use rustc_errors::{Diag, PResult};
 use rustc_hir as hir;
 use rustc_index::Idx;
 use rustc_infer::infer::TyCtxtInferExt;
@@ -35,11 +36,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         id: hir::HirId,
         span: Span,
     ) -> Box<Pat<'tcx>> {
-        let mut convert = ConstToPat::new(self, id, span);
+        let mut convert = ConstToPat::new(self, id, span, c);
 
         match c.kind() {
             ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty),
-            ty::ConstKind::Value(_, val) => convert.valtree_to_pat(val, ty),
+            ty::ConstKind::Value(_, val) => match convert.valtree_to_pat(val, ty) {
+                Ok(pat) => pat,
+                Err(err) => convert.mk_err(err, ty),
+            },
             _ => span_bug!(span, "Invalid `ConstKind` for `const_to_pat`: {:?}", c),
         }
     }
@@ -51,10 +55,12 @@ struct ConstToPat<'tcx> {
     span: Span,
 
     treat_byte_string_as_slice: bool,
+
+    c: ty::Const<'tcx>,
 }
 
 impl<'tcx> ConstToPat<'tcx> {
-    fn new(pat_ctxt: &PatCtxt<'_, 'tcx>, id: hir::HirId, span: Span) -> Self {
+    fn new(pat_ctxt: &PatCtxt<'_, 'tcx>, id: hir::HirId, span: Span, c: ty::Const<'tcx>) -> Self {
         trace!(?pat_ctxt.typeck_results.hir_owner);
         ConstToPat {
             tcx: pat_ctxt.tcx,
@@ -64,6 +70,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 .typeck_results
                 .treat_byte_string_as_slice
                 .contains(&id.local_id),
+            c,
         }
     }
 
@@ -71,13 +78,32 @@ impl<'tcx> ConstToPat<'tcx> {
         ty.is_structural_eq_shallow(self.tcx)
     }
 
+    /// We errored. Signal that in the pattern, so that follow up errors can be silenced.
+    fn mk_err(&self, mut err: Diag<'_>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
+        if let ty::ConstKind::Unevaluated(uv) = self.c.kind() {
+            let def_kind = self.tcx.def_kind(uv.def);
+            if let hir::def::DefKind::AssocConst = def_kind
+                && let Some(def_id) = uv.def.as_local()
+            {
+                // Include the container item in the output.
+                err.span_label(self.tcx.def_span(self.tcx.local_parent(def_id)), "");
+            }
+            if let hir::def::DefKind::Const | hir::def::DefKind::AssocConst = def_kind {
+                err.span_label(
+                    self.tcx.def_span(uv.def),
+                    crate::fluent_generated::mir_build_const_defined_here,
+                );
+            }
+        }
+        Box::new(Pat { span: self.span, ty, kind: PatKind::Error(err.emit()) })
+    }
+
     fn unevaluated_to_pat(
         &mut self,
         uv: ty::UnevaluatedConst<'tcx>,
         ty: Ty<'tcx>,
     ) -> Box<Pat<'tcx>> {
         trace!(self.treat_byte_string_as_slice);
-        let pat_from_kind = |kind| Box::new(Pat { span: self.span, ty, kind });
 
         // It's not *technically* correct to be revealing opaque types here as borrowcheck has
         // not run yet. However, CTFE itself uses `TypingMode::PostAnalysis` unconditionally even
@@ -96,44 +122,46 @@ impl<'tcx> ConstToPat<'tcx> {
             Ok(Ok(c)) => c,
             Err(ErrorHandled::Reported(_, _)) => {
                 // Let's tell the use where this failing const occurs.
-                let e = self.tcx.dcx().emit_err(CouldNotEvalConstPattern { span: self.span });
-                return pat_from_kind(PatKind::Error(e));
+                let err = self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span });
+                return self.mk_err(err, ty);
             }
             Err(ErrorHandled::TooGeneric(_)) => {
                 let e = self
                     .tcx
                     .dcx()
-                    .emit_err(ConstPatternDependsOnGenericParameter { span: self.span });
-                return pat_from_kind(PatKind::Error(e));
+                    .create_err(ConstPatternDependsOnGenericParameter { span: self.span });
+                return self.mk_err(e, ty);
             }
             Ok(Err(bad_ty)) => {
                 // The pattern cannot be turned into a valtree.
                 let e = match bad_ty.kind() {
                     ty::Adt(def, ..) => {
                         assert!(def.is_union());
-                        self.tcx.dcx().emit_err(UnionPattern { span: self.span })
+                        self.tcx.dcx().create_err(UnionPattern { span: self.span })
                     }
                     ty::FnPtr(..) | ty::RawPtr(..) => {
-                        self.tcx.dcx().emit_err(PointerPattern { span: self.span })
+                        self.tcx.dcx().create_err(PointerPattern { span: self.span })
                     }
                     _ => self
                         .tcx
                         .dcx()
-                        .emit_err(InvalidPattern { span: self.span, non_sm_ty: bad_ty }),
+                        .create_err(InvalidPattern { span: self.span, non_sm_ty: bad_ty }),
                 };
-                return pat_from_kind(PatKind::Error(e));
+                return self.mk_err(e, ty);
             }
         };
 
         // Convert the valtree to a const.
-        let inlined_const_as_pat = self.valtree_to_pat(valtree, ty);
+        let inlined_const_as_pat = match self.valtree_to_pat(valtree, ty) {
+            Ok(pat) => pat,
+            Err(err) => self.mk_err(err, ty),
+        };
 
         if !inlined_const_as_pat.references_error() {
             // Always check for `PartialEq` if we had no other errors yet.
             if !self.type_has_partial_eq_impl(ty) {
                 let err = TypeNotPartialEq { span: self.span, non_peq_ty: ty };
-                let e = self.tcx.dcx().emit_err(err);
-                return pat_from_kind(PatKind::Error(e));
+                return self.mk_err(self.tcx.dcx().create_err(err), ty);
             }
         }
 
@@ -175,14 +203,20 @@ impl<'tcx> ConstToPat<'tcx> {
                 let field = FieldIdx::new(idx);
                 // Patterns can only use monomorphic types.
                 let ty = self.tcx.normalize_erasing_regions(self.typing_env, ty);
-                FieldPat { field, pattern: self.valtree_to_pat(val, ty) }
+                FieldPat {
+                    field,
+                    pattern: match self.valtree_to_pat(val, ty) {
+                        Ok(pat) => pat,
+                        Err(err) => self.mk_err(err, ty),
+                    },
+                }
             })
             .collect()
     }
 
     // Recursive helper for `to_pat`; invoke that (instead of calling this directly).
     #[instrument(skip(self), level = "debug")]
-    fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
+    fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> PResult<'_, Box<Pat<'tcx>>> {
         let span = self.span;
         let tcx = self.tcx;
         let kind = match ty.kind() {
@@ -191,9 +225,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 // patterns.
                 debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty);
                 let err = TypeNotStructural { span, non_sm_ty: ty };
-                let e = tcx.dcx().emit_err(err);
-                // We errored. Signal that in the pattern, so that follow up errors can be silenced.
-                PatKind::Error(e)
+                return Err(tcx.dcx().create_err(err));
             }
             ty::Adt(adt_def, args) if adt_def.is_enum() => {
                 let (&variant_index, fields) = cv.unwrap_branch().split_first().unwrap();
@@ -227,7 +259,10 @@ impl<'tcx> ConstToPat<'tcx> {
                 prefix: cv
                     .unwrap_branch()
                     .iter()
-                    .map(|val| self.valtree_to_pat(*val, *elem_ty))
+                    .map(|val| match self.valtree_to_pat(*val, *elem_ty) {
+                        Ok(pat) => pat,
+                        Err(err) => self.mk_err(err, ty),
+                    })
                     .collect(),
                 slice: None,
                 suffix: Box::new([]),
@@ -236,7 +271,10 @@ impl<'tcx> ConstToPat<'tcx> {
                 prefix: cv
                     .unwrap_branch()
                     .iter()
-                    .map(|val| self.valtree_to_pat(*val, *elem_ty))
+                    .map(|val| match self.valtree_to_pat(*val, *elem_ty) {
+                        Ok(pat) => pat,
+                        Err(err) => self.mk_err(err, ty),
+                    })
                     .collect(),
                 slice: None,
                 suffix: Box::new([]),
@@ -252,10 +290,9 @@ impl<'tcx> ConstToPat<'tcx> {
                 // deref pattern.
                 _ => {
                     if !pointee_ty.is_sized(tcx, self.typing_env) && !pointee_ty.is_slice() {
-                        let err = UnsizedPattern { span, non_sm_ty: *pointee_ty };
-                        let e = tcx.dcx().emit_err(err);
-                        // We errored. Signal that in the pattern, so that follow up errors can be silenced.
-                        PatKind::Error(e)
+                        return Err(tcx
+                            .dcx()
+                            .create_err(UnsizedPattern { span, non_sm_ty: *pointee_ty }));
                     } else {
                         // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
                         // matching against references, you can only use byte string literals.
@@ -270,7 +307,10 @@ impl<'tcx> ConstToPat<'tcx> {
                             _ => *pointee_ty,
                         };
                         // References have the same valtree representation as their pointee.
-                        let subpattern = self.valtree_to_pat(cv, pointee_ty);
+                        let subpattern = match self.valtree_to_pat(cv, pointee_ty) {
+                            Ok(pat) => pat,
+                            Err(err) => self.mk_err(err, ty),
+                        };
                         PatKind::Deref { subpattern }
                     }
                 }
@@ -286,8 +326,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 if is_nan {
                     // NaNs are not ever equal to anything so they make no sense as patterns.
                     // Also see <https://github.com/rust-lang/rfcs/pull/3535>.
-                    let e = tcx.dcx().emit_err(NaNPattern { span });
-                    PatKind::Error(e)
+                    return Err(tcx.dcx().create_err(NaNPattern { span }));
                 } else {
                     PatKind::Constant {
                         value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)),
@@ -306,12 +345,10 @@ impl<'tcx> ConstToPat<'tcx> {
             }
             _ => {
                 let err = InvalidPattern { span, non_sm_ty: ty };
-                let e = tcx.dcx().emit_err(err);
-                // We errored. Signal that in the pattern, so that follow up errors can be silenced.
-                PatKind::Error(e)
+                return Err(tcx.dcx().create_err(err));
             }
         };
 
-        Box::new(Pat { span, ty, kind })
+        Ok(Box::new(Pat { span, ty, kind }))
     }
 }
diff --git a/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr b/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr
index adc8f3992072d..5aef0fa414bd4 100644
--- a/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr
+++ b/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr
@@ -1,24 +1,44 @@
 error[E0158]: constant pattern depends on a generic parameter
   --> $DIR/associated-const-type-parameter-pattern.rs:20:9
    |
+LL | pub trait Foo {
+   | -------------
+LL |     const X: EFoo;
+   |     ------------- constant defined here
+...
 LL |         A::X => println!("A::X"),
    |         ^^^^
 
 error[E0158]: constant pattern depends on a generic parameter
   --> $DIR/associated-const-type-parameter-pattern.rs:22:9
    |
+LL | pub trait Foo {
+   | -------------
+LL |     const X: EFoo;
+   |     ------------- constant defined here
+...
 LL |         B::X => println!("B::X"),
    |         ^^^^
 
 error[E0158]: constant pattern depends on a generic parameter
   --> $DIR/associated-const-type-parameter-pattern.rs:30:9
    |
+LL | pub trait Foo {
+   | -------------
+LL |     const X: EFoo;
+   |     ------------- constant defined here
+...
 LL |     let A::X = arg;
    |         ^^^^
 
 error[E0158]: constant pattern depends on a generic parameter
   --> $DIR/associated-const-type-parameter-pattern.rs:28:48
    |
+LL | pub trait Foo {
+   | -------------
+LL |     const X: EFoo;
+   |     ------------- constant defined here
+...
 LL | pub fn test_let_pat<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
    |                                                ^^^^
 
diff --git a/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr b/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr
index 9442eac0cf54a..9cce6fee55ac6 100644
--- a/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr
+++ b/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr
@@ -20,6 +20,11 @@ LL | pub struct Opcode2<S>(&'a S);
 error: could not evaluate constant pattern
   --> $DIR/ice-type-mismatch-when-copying-112824.rs:15:9
    |
+LL | impl Opcode2 {
+   | ------------
+LL |     pub const OP2: Opcode2 = Opcode2(Opcode(0x1));
+   |     ---------------------- constant defined here
+...
 LL |         Opcode2::OP2 => unimplemented!(),
    |         ^^^^^^^^^^^^
 
diff --git a/tests/ui/consts/const-eval/const-eval-overflow-2.stderr b/tests/ui/consts/const-eval/const-eval-overflow-2.stderr
index fc0baf11051b7..66c54af4f83f6 100644
--- a/tests/ui/consts/const-eval/const-eval-overflow-2.stderr
+++ b/tests/ui/consts/const-eval/const-eval-overflow-2.stderr
@@ -7,6 +7,9 @@ LL | const NEG_NEG_128: i8 = -NEG_128;
 error: could not evaluate constant pattern
   --> $DIR/const-eval-overflow-2.rs:15:9
    |
+LL | const NEG_NEG_128: i8 = -NEG_128;
+   | --------------------- constant defined here
+...
 LL |         NEG_NEG_128 => println!("A"),
    |         ^^^^^^^^^^^
 
diff --git a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr
index 8175fe6016ab8..b1c6cfd3246e2 100644
--- a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr
+++ b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr
@@ -12,6 +12,9 @@ error: could not evaluate constant pattern
    |
 LL |         10..=BAR => {},
    |              ^^^
+...
+LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
+   | -------------- constant defined here
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr b/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr
index e0f97a9abd210..81fc67e6aebb5 100644
--- a/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr
+++ b/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr
@@ -4,6 +4,11 @@ error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be ann
 LL |         consts::SOME => panic!(),
    |         ^^^^^^^^^^^^
    |
+  ::: $DIR/auxiliary/consts.rs:11:1
+   |
+LL | pub const SOME: Option<CustomEq> = Some(CustomEq);
+   | -------------------------------- constant defined here
+   |
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
@@ -13,6 +18,11 @@ error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be ann
 LL |         <Defaulted as consts::AssocConst>::SOME  => panic!(),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+  ::: $DIR/auxiliary/consts.rs:15:5
+   |
+LL |     const SOME: Option<CustomEq> = Some(CustomEq);
+   |     ---------------------------- constant defined here
+   |
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
diff --git a/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr b/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr
index aa208341c131d..cc7ec771e6cd6 100644
--- a/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr
+++ b/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr
@@ -1,24 +1,36 @@
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:9:9
    |
+LL | const C: *const u8 = &0;
+   | ------------------ constant defined here
+...
 LL |         C => {}
    |         ^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:16:9
    |
+LL | const C_INNER: (*const u8, u8) = (C, 0);
+   | ------------------------------ constant defined here
+...
 LL |         C_INNER => {}
    |         ^^^^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:27:9
    |
+LL | const D: *const [u8; 4] = b"abcd";
+   | ----------------------- constant defined here
+...
 LL |         D => {}
    |         ^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:32:9
    |
+LL | const STR: *const str = "abcd";
+   | --------------------- constant defined here
+...
 LL |         STR => {}
    |         ^^^
 
diff --git a/tests/ui/consts/const_in_pattern/issue-44333.stderr b/tests/ui/consts/const_in_pattern/issue-44333.stderr
index d377bfd95f9cd..81393952f0fcf 100644
--- a/tests/ui/consts/const_in_pattern/issue-44333.stderr
+++ b/tests/ui/consts/const_in_pattern/issue-44333.stderr
@@ -1,12 +1,18 @@
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/issue-44333.rs:15:9
    |
+LL | const FOO: Func = foo;
+   | --------------- constant defined here
+...
 LL |         FOO => println!("foo"),
    |         ^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/issue-44333.rs:16:9
    |
+LL | const BAR: Func = bar;
+   | --------------- constant defined here
+...
 LL |         BAR => println!("bar"),
    |         ^^^
 
diff --git a/tests/ui/consts/const_in_pattern/issue-65466.stderr b/tests/ui/consts/const_in_pattern/issue-65466.stderr
index 7d5e5b5b0c64a..070ce384f6aad 100644
--- a/tests/ui/consts/const_in_pattern/issue-65466.stderr
+++ b/tests/ui/consts/const_in_pattern/issue-65466.stderr
@@ -1,6 +1,9 @@
 error: to use a constant of type `&[O<B>]` in a pattern, the type must implement `PartialEq`
   --> $DIR/issue-65466.rs:14:9
    |
+LL | const C: &[O<B>] = &[O::None];
+   | ---------------- constant defined here
+...
 LL |         C => (),
    |         ^
 
diff --git a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr
index 7766c6ce683d2..5e2fc6eca3c5d 100644
--- a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr
+++ b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr
@@ -1,6 +1,9 @@
 error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/no-eq-branch-fail.rs:19:9
    |
+LL | const BAR_BAZ: Foo = if 42 == 42 {
+   | ------------------ constant defined here
+...
 LL |         BAR_BAZ => panic!(),
    |         ^^^^^^^
    |
diff --git a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
index ed531a1fead8d..463b37e7caa73 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
+++ b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
@@ -1,6 +1,9 @@
 error: to use a constant of type `Option<NoPartialEq>` in a pattern, the type must implement `PartialEq`
   --> $DIR/reject_non_partial_eq.rs:28:9
    |
+LL | const NO_PARTIAL_EQ_NONE: Option<NoPartialEq> = None;
+   | --------------------------------------------- constant defined here
+...
 LL |         NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"),
    |         ^^^^^^^^^^^^^^^^^^
 
diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.rs b/tests/ui/consts/const_in_pattern/reject_non_structural.rs
index e3dcecec960a7..52cb974c1df1b 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_structural.rs
+++ b/tests/ui/consts/const_in_pattern/reject_non_structural.rs
@@ -36,63 +36,63 @@ fn main() {
     #[derive(PartialEq, Eq, Debug)]
     enum Derive<X> { Some(X), None, }
 
-    const ENUM: Derive<NoDerive> = Derive::Some(NoDerive);
+    const ENUM: Derive<NoDerive> = Derive::Some(NoDerive); //~ NOTE constant defined here
     match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), };
     //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
     //~| NOTE StructuralPartialEq.html for details
 
-    const FIELD: OND = TrivialEq(Some(NoDerive)).0;
+    const FIELD: OND = TrivialEq(Some(NoDerive)).0; //~ NOTE constant defined here
     match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), };
     //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
     //~| NOTE StructuralPartialEq.html for details
 
     const NO_DERIVE_SOME: OND = Some(NoDerive);
-    const INDIRECT: OND = NO_DERIVE_SOME;
+    const INDIRECT: OND = NO_DERIVE_SOME; //~ NOTE constant defined here
     match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), };
     //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
     //~| NOTE StructuralPartialEq.html for details
 
-    const TUPLE: (OND, OND) = (None, Some(NoDerive));
+    const TUPLE: (OND, OND) = (None, Some(NoDerive)); //~ NOTE constant defined here
     match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), };
     //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
     //~| NOTE StructuralPartialEq.html for details
 
-    const TYPE_ASCRIPTION: OND = type_ascribe!(Some(NoDerive), OND);
+    const TYPE_ASCRIPTION: OND = type_ascribe!(Some(NoDerive), OND); //~ NOTE constant defined here
     match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), };
     //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
     //~| NOTE StructuralPartialEq.html for details
 
-    const ARRAY: [OND; 2] = [None, Some(NoDerive)];
+    const ARRAY: [OND; 2] = [None, Some(NoDerive)]; //~ NOTE constant defined here
     match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), };
     //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
     //~| NOTE StructuralPartialEq.html for details
 
-    const REPEAT: [OND; 2] = [Some(NoDerive); 2];
+    const REPEAT: [OND; 2] = [Some(NoDerive); 2]; //~ NOTE constant defined here
     match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), };
     //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
     //~| NOTE StructuralPartialEq.html for details
 
-    trait Trait: Sized { const ASSOC: Option<Self>; }
+    trait Trait: Sized { const ASSOC: Option<Self>; } //~ NOTE constant defined here
     impl Trait for NoDerive { const ASSOC: Option<NoDerive> = Some(NoDerive); }
     match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), };
     //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
     //~| NOTE StructuralPartialEq.html for details
 
-    const BLOCK: OND = { NoDerive; Some(NoDerive) };
+    const BLOCK: OND = { NoDerive; Some(NoDerive) }; //~ NOTE constant defined here
     match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), };
     //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
     //~| NOTE StructuralPartialEq.html for details
 
-    const ADDR_OF: &OND = &Some(NoDerive);
+    const ADDR_OF: &OND = &Some(NoDerive); //~ NOTE constant defined here
     match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), };
     //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
index c068db42e4d90..e8a69512e7eda 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
+++ b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
@@ -1,6 +1,8 @@
 error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:40:36
    |
+LL |     const ENUM: Derive<NoDerive> = Derive::Some(NoDerive);
+   |     ---------------------------- constant defined here
 LL |     match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), };
    |                                    ^^^^
    |
@@ -10,6 +12,8 @@ LL |     match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"
 error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:46:28
    |
+LL |     const FIELD: OND = TrivialEq(Some(NoDerive)).0;
+   |     ---------------- constant defined here
 LL |     match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), };
    |                            ^^^^^
    |
@@ -19,6 +23,8 @@ LL |     match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), };
 error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:53:27
    |
+LL |     const INDIRECT: OND = NO_DERIVE_SOME;
+   |     ------------------- constant defined here
 LL |     match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), };
    |                           ^^^^^^^^
    |
@@ -28,6 +34,8 @@ LL |     match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops")
 error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:59:36
    |
+LL |     const TUPLE: (OND, OND) = (None, Some(NoDerive));
+   |     ----------------------- constant defined here
 LL |     match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), };
    |                                    ^^^^^
    |
@@ -37,6 +45,8 @@ LL |     match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoop
 error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:65:28
    |
+LL |     const TYPE_ASCRIPTION: OND = type_ascribe!(Some(NoDerive), OND);
+   |     -------------------------- constant defined here
 LL |     match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), };
    |                            ^^^^^^^^^^^^^^^
    |
@@ -46,6 +56,8 @@ LL |     match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => p
 error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:71:36
    |
+LL |     const ARRAY: [OND; 2] = [None, Some(NoDerive)];
+   |     --------------------- constant defined here
 LL |     match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), };
    |                                    ^^^^^
    |
@@ -55,6 +67,8 @@ LL |     match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoop
 error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:77:33
    |
+LL |     const REPEAT: [OND; 2] = [Some(NoDerive); 2];
+   |     ---------------------- constant defined here
 LL |     match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), };
    |                                 ^^^^^^
    |
@@ -64,6 +78,9 @@ LL |     match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops
 error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:84:28
    |
+LL |     trait Trait: Sized { const ASSOC: Option<Self>; }
+   |     ------------------   ------------------------- constant defined here
+LL |     impl Trait for NoDerive { const ASSOC: Option<NoDerive> = Some(NoDerive); }
 LL |     match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), };
    |                            ^^^^^^^^^^^^^^^
    |
@@ -73,6 +90,8 @@ LL |     match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => p
 error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:90:28
    |
+LL |     const BLOCK: OND = { NoDerive; Some(NoDerive) };
+   |     ---------------- constant defined here
 LL |     match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), };
    |                            ^^^^^
    |
@@ -82,6 +101,8 @@ LL |     match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), };
 error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:96:29
    |
+LL |     const ADDR_OF: &OND = &Some(NoDerive);
+   |     ------------------- constant defined here
 LL |     match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), };
    |                             ^^^^^^^
    |
diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr
index 0153f501174b2..9f2633a64d594 100644
--- a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr
+++ b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr
@@ -34,18 +34,27 @@ LL |     const C: &i32 = unsafe { &S_MUT };
 error: could not evaluate constant pattern
   --> $DIR/const_refs_to_static_fail_invalid.rs:14:9
    |
+LL |     const C: &bool = unsafe { std::mem::transmute(&S) };
+   |     -------------- constant defined here
+...
 LL |         C => {}
    |         ^
 
 error: could not evaluate constant pattern
   --> $DIR/const_refs_to_static_fail_invalid.rs:30:9
    |
+LL |     const C: &i8 = unsafe { &S };
+   |     ------------ constant defined here
+...
 LL |         C => {}
    |         ^
 
 error: could not evaluate constant pattern
   --> $DIR/const_refs_to_static_fail_invalid.rs:45:9
    |
+LL |     const C: &i32 = unsafe { &S_MUT };
+   |     ------------- constant defined here
+...
 LL |         C => {}
    |         ^
 
diff --git a/tests/ui/consts/issue-43105.stderr b/tests/ui/consts/issue-43105.stderr
index 856a8f0dab6c0..4c59bdd4520eb 100644
--- a/tests/ui/consts/issue-43105.stderr
+++ b/tests/ui/consts/issue-43105.stderr
@@ -9,6 +9,9 @@ LL | const NUM: u8 = xyz();
 error: could not evaluate constant pattern
   --> $DIR/issue-43105.rs:8:9
    |
+LL | const NUM: u8 = xyz();
+   | ------------- constant defined here
+...
 LL |         NUM => unimplemented!(),
    |         ^^^
 
diff --git a/tests/ui/consts/issue-73976-polymorphic.stderr b/tests/ui/consts/issue-73976-polymorphic.stderr
index 8a44eb9854fef..79a03d4ec32c9 100644
--- a/tests/ui/consts/issue-73976-polymorphic.stderr
+++ b/tests/ui/consts/issue-73976-polymorphic.stderr
@@ -1,12 +1,22 @@
 error[E0158]: constant pattern depends on a generic parameter
   --> $DIR/issue-73976-polymorphic.rs:20:37
    |
+LL | impl<T: 'static> GetTypeId<T> {
+   | -----------------------------
+LL |     pub const VALUE: TypeId = TypeId::of::<T>();
+   |     ----------------------- constant defined here
+...
 LL |     matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
    |                                     ^^^^^^^^^^^^^^^^^^^^^
 
 error[E0158]: constant pattern depends on a generic parameter
   --> $DIR/issue-73976-polymorphic.rs:31:42
    |
+LL | impl<T: 'static> GetTypeNameLen<T> {
+   | ----------------------------------
+LL |     pub const VALUE: usize = any::type_name::<T>().len();
+   |     ---------------------- constant defined here
+...
 LL |     matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/tests/ui/consts/issue-78655.stderr b/tests/ui/consts/issue-78655.stderr
index ccaed03b4c1df..5d684227be8bf 100644
--- a/tests/ui/consts/issue-78655.stderr
+++ b/tests/ui/consts/issue-78655.stderr
@@ -14,6 +14,9 @@ LL |     let x = 42;
 error: could not evaluate constant pattern
   --> $DIR/issue-78655.rs:7:9
    |
+LL | const FOO: *const u32 = {
+   | --------------------- constant defined here
+...
 LL |     let FOO = FOO;
    |         ^^^
 
diff --git a/tests/ui/consts/issue-79137-toogeneric.stderr b/tests/ui/consts/issue-79137-toogeneric.stderr
index de81512ec6d2c..9b53a2595479d 100644
--- a/tests/ui/consts/issue-79137-toogeneric.stderr
+++ b/tests/ui/consts/issue-79137-toogeneric.stderr
@@ -1,6 +1,11 @@
 error[E0158]: constant pattern depends on a generic parameter
   --> $DIR/issue-79137-toogeneric.rs:12:43
    |
+LL | impl<T> GetVariantCount<T> {
+   | --------------------------
+LL |     pub const VALUE: usize = std::mem::variant_count::<T>();
+   |     ---------------------- constant defined here
+...
 LL |     matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE)
    |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/tests/ui/consts/issue-87046.stderr b/tests/ui/consts/issue-87046.stderr
index 0f965e1ac3f1b..36e2564fae6b0 100644
--- a/tests/ui/consts/issue-87046.stderr
+++ b/tests/ui/consts/issue-87046.stderr
@@ -1,6 +1,9 @@
 error: cannot use unsized non-slice type `Username` in constant patterns
   --> $DIR/issue-87046.rs:28:13
    |
+LL | pub const ROOT_USER: &Username = Username::from_str("root");
+   | ------------------------------ constant defined here
+...
 LL |             ROOT_USER => true,
    |             ^^^^^^^^^
 
diff --git a/tests/ui/consts/issue-89088.stderr b/tests/ui/consts/issue-89088.stderr
index 362c63a2a4569..740cc25647e52 100644
--- a/tests/ui/consts/issue-89088.stderr
+++ b/tests/ui/consts/issue-89088.stderr
@@ -1,6 +1,9 @@
 error: to use a constant of type `Cow<'_, str>` in a pattern, `Cow<'_, str>` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/issue-89088.rs:16:9
    |
+LL | const FOO: &A = &A::Field(Cow::Borrowed("foo"));
+   | ------------- constant defined here
+...
 LL |         FOO => todo!(),
    |         ^^^
    |
diff --git a/tests/ui/consts/match_ice.stderr b/tests/ui/consts/match_ice.stderr
index 472c24a5cbe31..0841ed050251a 100644
--- a/tests/ui/consts/match_ice.stderr
+++ b/tests/ui/consts/match_ice.stderr
@@ -1,6 +1,9 @@
 error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/match_ice.rs:11:9
    |
+LL |     const C: &S = &S;
+   |     ----------- constant defined here
+LL |     match C {
 LL |         C => {}
    |         ^
    |
diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr
index 147d3f238f777..513f456bdf4e6 100644
--- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr
+++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr
@@ -40,24 +40,36 @@ LL |         match static_cross_crate::OPT_ZERO {
 error: could not evaluate constant pattern
   --> $DIR/const_refers_to_static_cross_crate.rs:40:9
    |
+LL | const SLICE_MUT: &[u8; 1] = {
+   | ------------------------- constant defined here
+...
 LL |         SLICE_MUT => true,
    |         ^^^^^^^^^
 
 error: could not evaluate constant pattern
   --> $DIR/const_refers_to_static_cross_crate.rs:48:9
    |
+LL | const U8_MUT: &u8 = {
+   | ----------------- constant defined here
+...
 LL |         U8_MUT => true,
    |         ^^^^^^
 
 error: could not evaluate constant pattern
   --> $DIR/const_refers_to_static_cross_crate.rs:58:9
    |
+LL | const U8_MUT2: &u8 = {
+   | ------------------ constant defined here
+...
 LL |         U8_MUT2 => true,
    |         ^^^^^^^
 
 error: could not evaluate constant pattern
   --> $DIR/const_refers_to_static_cross_crate.rs:65:9
    |
+LL | const U8_MUT3: &u8 = {
+   | ------------------ constant defined here
+...
 LL |         U8_MUT3 => true,
    |         ^^^^^^^
 
diff --git a/tests/ui/consts/missing_assoc_const_type.stderr b/tests/ui/consts/missing_assoc_const_type.stderr
index ef7ff962d2d12..8123a43ef74fe 100644
--- a/tests/ui/consts/missing_assoc_const_type.stderr
+++ b/tests/ui/consts/missing_assoc_const_type.stderr
@@ -7,6 +7,11 @@ LL |     const FIRST:  = 10;
 error: could not evaluate constant pattern
   --> $DIR/missing_assoc_const_type.rs:19:9
    |
+LL | trait Range {
+   | -----------
+LL |     const FIRST: u8;
+   |     --------------- constant defined here
+...
 LL |         TwoDigits::FIRST..=TwoDigits::LAST => 0,
    |         ^^^^^^^^^^^^^^^^
 
diff --git a/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr b/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr
index e0d658db99760..79f59ba865d8d 100644
--- a/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr
+++ b/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr
@@ -12,6 +12,9 @@ error: could not evaluate constant pattern
    |
 LL |         ZST => {}
    |         ^^^
+...
+LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
+   | ---------------- constant defined here
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/match/issue-70972-dyn-trait.stderr b/tests/ui/match/issue-70972-dyn-trait.stderr
index b0af50f8599c5..91f49c8a2ff10 100644
--- a/tests/ui/match/issue-70972-dyn-trait.stderr
+++ b/tests/ui/match/issue-70972-dyn-trait.stderr
@@ -1,6 +1,9 @@
 error: `dyn Send` cannot be used in patterns
   --> $DIR/issue-70972-dyn-trait.rs:6:9
    |
+LL | const F: &'static dyn Send = &7u32;
+   | -------------------------- constant defined here
+...
 LL |         F => panic!(),
    |         ^
 
diff --git a/tests/ui/match/issue-72896-non-partial-eq-const.stderr b/tests/ui/match/issue-72896-non-partial-eq-const.stderr
index 4155586c16060..eeca541fc3cd8 100644
--- a/tests/ui/match/issue-72896-non-partial-eq-const.stderr
+++ b/tests/ui/match/issue-72896-non-partial-eq-const.stderr
@@ -1,6 +1,9 @@
 error: to use a constant of type `EnumSet<Enum8>` in a pattern, the type must implement `PartialEq`
   --> $DIR/issue-72896-non-partial-eq-const.rs:19:9
    |
+LL | const CONST_SET: EnumSet<Enum8> = EnumSet { __enumset_underlying: 3 };
+   | ------------------------------- constant defined here
+...
 LL |         CONST_SET => { /* ok */ }
    |         ^^^^^^^^^
 
diff --git a/tests/ui/pattern/issue-115599.stderr b/tests/ui/pattern/issue-115599.stderr
index adab4e4d241b7..65e3b08ac4853 100644
--- a/tests/ui/pattern/issue-115599.stderr
+++ b/tests/ui/pattern/issue-115599.stderr
@@ -1,6 +1,9 @@
 error: to use a constant of type `Vec<u8>` in a pattern, `Vec<u8>` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/issue-115599.rs:5:12
    |
+LL | const CONST_STRING: String = String::new();
+   | -------------------------- constant defined here
+...
 LL |     if let CONST_STRING = empty_str {}
    |            ^^^^^^^^^^^^
    |
diff --git a/tests/ui/pattern/issue-72565.stderr b/tests/ui/pattern/issue-72565.stderr
index b503a17fe849f..abfd4512e9b8e 100644
--- a/tests/ui/pattern/issue-72565.stderr
+++ b/tests/ui/pattern/issue-72565.stderr
@@ -1,6 +1,9 @@
 error: `dyn PartialEq<u32>` cannot be used in patterns
   --> $DIR/issue-72565.rs:6:9
    |
+LL | const F: &'static dyn PartialEq<u32> = &7u32;
+   | ------------------------------------ constant defined here
+...
 LL |         F => panic!(),
    |         ^
 
diff --git a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
index 0b4d99727581b..bcbcd0bc280d8 100644
--- a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
+++ b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
@@ -1,6 +1,9 @@
 error: to use a constant of type `MyType` in a pattern, `MyType` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/const-partial_eq-fallback-ice.rs:14:12
    |
+LL | const CONSTANT: &&MyType = &&MyType;
+   | ------------------------ constant defined here
+...
 LL |     if let CONSTANT = &&MyType {
    |            ^^^^^^^^
    |
diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr
index 32d385eecb476..15aa1769662cd 100644
--- a/tests/ui/pattern/usefulness/consts-opaque.stderr
+++ b/tests/ui/pattern/usefulness/consts-opaque.stderr
@@ -1,48 +1,72 @@
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:96:9
    |
+LL |     const QUUX: Quux = quux;
+   |     ---------------- constant defined here
+...
 LL |         QUUX => {}
    |         ^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:97:9
    |
+LL |     const QUUX: Quux = quux;
+   |     ---------------- constant defined here
+...
 LL |         QUUX => {}
    |         ^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:106:9
    |
+LL |     const WRAPQUUX: Wrap<Quux> = Wrap(quux);
+   |     -------------------------- constant defined here
+...
 LL |         WRAPQUUX => {}
    |         ^^^^^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:107:9
    |
+LL |     const WRAPQUUX: Wrap<Quux> = Wrap(quux);
+   |     -------------------------- constant defined here
+...
 LL |         WRAPQUUX => {}
    |         ^^^^^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:113:9
    |
+LL |     const WRAPQUUX: Wrap<Quux> = Wrap(quux);
+   |     -------------------------- constant defined here
+...
 LL |         WRAPQUUX => {}
    |         ^^^^^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:121:9
    |
+LL |     const WRAPQUUX: Wrap<Quux> = Wrap(quux);
+   |     -------------------------- constant defined here
+...
 LL |         WRAPQUUX => {}
    |         ^^^^^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:132:9
    |
+LL |     const WHOKNOWSQUUX: WhoKnows<Quux> = WhoKnows::Yay(quux);
+   |     ---------------------------------- constant defined here
+...
 LL |         WHOKNOWSQUUX => {}
    |         ^^^^^^^^^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/consts-opaque.rs:134:9
    |
+LL |     const WHOKNOWSQUUX: WhoKnows<Quux> = WhoKnows::Yay(quux);
+   |     ---------------------------------- constant defined here
+...
 LL |         WHOKNOWSQUUX => {}
    |         ^^^^^^^^^^^^
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr
index cc5d4106331d2..dffaafd88a088 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr
@@ -1,6 +1,9 @@
 error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/cant-hide-behind-direct-struct-embedded.rs:22:9
    |
+LL | const WRAP_DIRECT_INLINE: WrapInline = WrapInline(NoDerive(0));
+   | ------------------------------------ constant defined here
+...
 LL |         WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); }
    |         ^^^^^^^^^^^^^^^^^^
    |
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr
index 3d00ef2dfbf6d..8da9fa71c536a 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr
@@ -1,6 +1,9 @@
 error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/cant-hide-behind-direct-struct-param.rs:21:9
    |
+LL | const WRAP_DIRECT_PARAM: WrapParam<NoDerive> = WrapParam(NoDerive(0));
+   | -------------------------------------------- constant defined here
+...
 LL |         WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); }
    |         ^^^^^^^^^^^^^^^^^
    |
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr
index 3636307e16c61..3cd6a184bbe20 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr
@@ -1,6 +1,9 @@
 error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:22:9
    |
+LL | const WRAP_DOUBLY_INDIRECT_INLINE: & &WrapInline = & &WrapInline(& & NoDerive(0));
+   | ------------------------------------------------ constant defined here
+...
 LL |         WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr
index 40fd31762b2fe..35693da99abf3 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr
@@ -1,6 +1,9 @@
 error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/cant-hide-behind-doubly-indirect-param.rs:22:9
    |
+LL | const WRAP_DOUBLY_INDIRECT_PARAM: & &WrapParam<NoDerive> = & &WrapParam(& & NoDerive(0));
+   | -------------------------------------------------------- constant defined here
+...
 LL |         WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr
index dbf1848326aa4..5312d61c44695 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr
@@ -1,6 +1,9 @@
 error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:22:9
    |
+LL | const WRAP_INDIRECT_INLINE: & &WrapInline = & &WrapInline(NoDerive(0));
+   | ----------------------------------------- constant defined here
+...
 LL |         WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); }
    |         ^^^^^^^^^^^^^^^^^^^^
    |
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr
index 58acc11a74498..2066c53e73a6b 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr
@@ -1,6 +1,9 @@
 error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/cant-hide-behind-indirect-struct-param.rs:22:9
    |
+LL | const WRAP_INDIRECT_PARAM: & &WrapParam<NoDerive> = & &WrapParam(NoDerive(0));
+   | ------------------------------------------------- constant defined here
+...
 LL |         WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); }
    |         ^^^^^^^^^^^^^^^^^^^
    |
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-not-structurally-matchable.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-not-structurally-matchable.stderr
index 0bc1e7fc89b5f..ee6f44a364da4 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-not-structurally-matchable.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-not-structurally-matchable.stderr
@@ -1,60 +1,90 @@
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:41:14
    |
+LL |     const CFN1: Wrap<fn()> = Wrap(trivial);
+   |     ---------------------- constant defined here
+...
 LL |         Wrap(CFN1) => count += 1,
    |              ^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:49:14
    |
+LL |     const CFN2: Wrap<fn(SM)> = Wrap(sm_to);
+   |     ------------------------ constant defined here
+...
 LL |         Wrap(CFN2) => count += 1,
    |              ^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:57:14
    |
+LL |     const CFN3: Wrap<fn() -> SM> = Wrap(to_sm);
+   |     ---------------------------- constant defined here
+...
 LL |         Wrap(CFN3) => count += 1,
    |              ^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:65:14
    |
+LL |     const CFN4: Wrap<fn(NotSM)> = Wrap(not_sm_to);
+   |     --------------------------- constant defined here
+...
 LL |         Wrap(CFN4) => count += 1,
    |              ^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:73:14
    |
+LL |     const CFN5: Wrap<fn() -> NotSM> = Wrap(to_not_sm);
+   |     ------------------------------- constant defined here
+...
 LL |         Wrap(CFN5) => count += 1,
    |              ^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:81:14
    |
+LL |     const CFN6: Wrap<fn(&SM)> = Wrap(r_sm_to);
+   |     ------------------------- constant defined here
+...
 LL |         Wrap(CFN6) => count += 1,
    |              ^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:89:14
    |
+LL |     const CFN7: Wrap<fn(&()) -> &SM> = Wrap(r_to_r_sm);
+   |     -------------------------------- constant defined here
+...
 LL |         Wrap(CFN7) => count += 1,
    |              ^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:97:14
    |
+LL |     const CFN8: Wrap<fn(&NotSM)> = Wrap(r_not_sm_to);
+   |     ---------------------------- constant defined here
+...
 LL |         Wrap(CFN8) => count += 1,
    |              ^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:105:14
    |
+LL |     const CFN9: Wrap<fn(&()) -> &NotSM> = Wrap(r_to_r_not_sm);
+   |     ----------------------------------- constant defined here
+...
 LL |         Wrap(CFN9) => count += 1,
    |              ^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:127:9
    |
+LL |     const CFOO: Foo = Foo {
+   |     --------------- constant defined here
+...
 LL |         CFOO => count += 1,
    |         ^^^^
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
index 736e4c30c8ae3..e105c6a1f98a9 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
@@ -1,6 +1,9 @@
 error: to use a constant of type `&[B]` in a pattern, the type must implement `PartialEq`
   --> $DIR/issue-61188-match-slice-forbidden-without-eq.rs:15:9
    |
+LL | const A: &[B] = &[];
+   | ------------- constant defined here
+...
 LL |         A => (),
    |         ^
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr
index e79b05fdf9dc6..5cfe6dabc8956 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr
@@ -1,6 +1,9 @@
 error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:29:9
    |
+LL |     const RR_B1: & & B = & & B(1);
+   |     ------------------ constant defined here
+...
 LL |         RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); }
    |         ^^^^^
    |
@@ -10,6 +13,9 @@ LL |         RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0);
 error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:35:9
    |
+LL |     const RR_B1: & & B = & & B(1);
+   |     ------------------ constant defined here
+...
 LL |         RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); }
    |         ^^^^^
    |
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr
index 7b1832ed0fa58..be735ccab0a5a 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr
@@ -1,12 +1,18 @@
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/issue-63479-match-fnptr.rs:32:7
    |
+LL | const TEST: Fn = my_fn;
+   | -------------- constant defined here
+...
 LL |     B(TEST) => println!("matched"),
    |       ^^^^
 
 error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
   --> $DIR/issue-63479-match-fnptr.rs:37:5
    |
+LL | const TEST2: (Fn, u8) = (TEST, 0);
+   | --------------------- constant defined here
+...
 LL |     TEST2 => println!("matched"),
    |     ^^^^^
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr
index 44b05ea31e962..4e2dcb52da807 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr
@@ -1,6 +1,9 @@
 error: cannot use NaN in patterns
   --> $DIR/issue-6804-nan-match.rs:14:9
    |
+LL | const NAN: f64 = f64::NAN;
+   | -------------- constant defined here
+...
 LL |         NAN => {},
    |         ^^^
    |
@@ -10,6 +13,9 @@ LL |         NAN => {},
 error: cannot use NaN in patterns
   --> $DIR/issue-6804-nan-match.rs:19:10
    |
+LL | const NAN: f64 = f64::NAN;
+   | -------------- constant defined here
+...
 LL |         [NAN, _] => {},
    |          ^^^
    |
@@ -19,6 +25,9 @@ LL |         [NAN, _] => {},
 error: cannot use NaN in patterns
   --> $DIR/issue-6804-nan-match.rs:24:9
    |
+LL | const C: MyType<f32> = MyType(f32::NAN);
+   | -------------------- constant defined here
+...
 LL |         C => {},
    |         ^
    |
@@ -28,6 +37,9 @@ LL |         C => {},
 error: cannot use NaN in patterns
   --> $DIR/issue-6804-nan-match.rs:30:9
    |
+LL | const NAN: f64 = f64::NAN;
+   | -------------- constant defined here
+...
 LL |         NAN..=1.0 => {},
    |         ^^^
    |
@@ -37,6 +49,9 @@ LL |         NAN..=1.0 => {},
 error: cannot use NaN in patterns
   --> $DIR/issue-6804-nan-match.rs:31:16
    |
+LL | const NAN: f64 = f64::NAN;
+   | -------------- constant defined here
+...
 LL |         -1.0..=NAN => {},
    |                ^^^
    |
@@ -46,6 +61,9 @@ LL |         -1.0..=NAN => {},
 error: cannot use NaN in patterns
   --> $DIR/issue-6804-nan-match.rs:32:9
    |
+LL | const NAN: f64 = f64::NAN;
+   | -------------- constant defined here
+...
 LL |         NAN.. => {},
    |         ^^^
    |
@@ -55,6 +73,9 @@ LL |         NAN.. => {},
 error: cannot use NaN in patterns
   --> $DIR/issue-6804-nan-match.rs:33:11
    |
+LL | const NAN: f64 = f64::NAN;
+   | -------------- constant defined here
+...
 LL |         ..NAN => {},
    |           ^^^
    |
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr
index efd9c8c45afa9..c471fe572548c 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr
@@ -1,6 +1,9 @@
 error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/match-requires-both-partialeq-and-eq.rs:17:9
    |
+LL | const FOO: Foo = Foo { x: 0 };
+   | -------------- constant defined here
+...
 LL |         FOO => { }
    |         ^^^
    |
diff --git a/tests/ui/type-alias-impl-trait/structural-match-no-leak.stderr b/tests/ui/type-alias-impl-trait/structural-match-no-leak.stderr
index 98d71aa9a17dc..743ad75628e25 100644
--- a/tests/ui/type-alias-impl-trait/structural-match-no-leak.stderr
+++ b/tests/ui/type-alias-impl-trait/structural-match-no-leak.stderr
@@ -1,6 +1,9 @@
 error: `Bar` cannot be used in patterns
   --> $DIR/structural-match-no-leak.rs:16:9
    |
+LL | const LEAK_FREE: bar::Bar = bar::leak_free();
+   | ------------------------- constant defined here
+...
 LL |         LEAK_FREE => (),
    |         ^^^^^^^^^
 
diff --git a/tests/ui/type-alias-impl-trait/structural-match.stderr b/tests/ui/type-alias-impl-trait/structural-match.stderr
index c7478b0a135e5..9c26aa9a9a645 100644
--- a/tests/ui/type-alias-impl-trait/structural-match.stderr
+++ b/tests/ui/type-alias-impl-trait/structural-match.stderr
@@ -1,6 +1,9 @@
 error: `foo::Foo` cannot be used in patterns
   --> $DIR/structural-match.rs:18:9
    |
+LL | const VALUE: Foo = value();
+   | ---------------- constant defined here
+...
 LL |         VALUE => (),
    |         ^^^^^
 
diff --git a/tests/ui/union/union-const-pat.stderr b/tests/ui/union/union-const-pat.stderr
index e9dbb275944ae..baf32bf484950 100644
--- a/tests/ui/union/union-const-pat.stderr
+++ b/tests/ui/union/union-const-pat.stderr
@@ -1,6 +1,9 @@
 error: cannot use unions in constant patterns
   --> $DIR/union-const-pat.rs:10:9
    |
+LL | const C: U = U { a: 10 };
+   | ---------- constant defined here
+...
 LL |         C => {}
    |         ^
 

From cc492edc9d65125a25a42446bbffefb8087dedf1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 20 Nov 2024 02:37:56 +0000
Subject: [PATCH 09/21] Tweak unevaluated constant in pattern error

Silence errors that are implied by the errors in the `const` item definition.

Add a primary span label.
---
 compiler/rustc_mir_build/messages.ftl         |  1 +
 compiler/rustc_mir_build/src/errors.rs        |  1 +
 .../src/thir/pattern/const_to_pat.rs          | 11 +++++-
 .../ice-type-mismatch-when-copying-112824.rs  |  3 +-
 ...e-type-mismatch-when-copying-112824.stderr | 13 +------
 .../const-eval/const-eval-overflow-2.rs       |  3 +-
 .../const-eval/const-eval-overflow-2.stderr   | 11 +-----
 .../const-eval/ref_to_int_match.64bit.stderr  | 11 +-----
 .../ui/consts/const-eval/ref_to_int_match.rs  |  2 +-
 .../const_refs_to_static_fail_invalid.rs      |  6 +--
 .../const_refs_to_static_fail_invalid.stderr  | 29 +-------------
 .../invalid-inline-const-in-match-arm.stderr  |  2 +-
 tests/ui/consts/issue-43105.rs                |  3 +-
 tests/ui/consts/issue-43105.stderr            | 11 +-----
 tests/ui/consts/issue-78655.rs                |  3 +-
 tests/ui/consts/issue-78655.stderr            | 11 +-----
 .../const_refers_to_static_cross_crate.rs     | 12 ++----
 .../const_refers_to_static_cross_crate.stderr | 38 +------------------
 tests/ui/consts/missing_assoc_const_type.rs   |  5 +--
 .../ui/consts/missing_assoc_const_type.stderr | 13 +------
 .../transmute-size-mismatch-before-typeck.rs  |  2 +-
 ...ansmute-size-mismatch-before-typeck.stderr | 11 +-----
 22 files changed, 37 insertions(+), 165 deletions(-)

diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index fdefc0bfd190c..ad2f13f6d21ab 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -92,6 +92,7 @@ mir_build_const_pattern_depends_on_generic_parameter =
     constant pattern depends on a generic parameter
 
 mir_build_could_not_eval_const_pattern = could not evaluate constant pattern
+    .label = could not evaluate constant
 
 mir_build_deref_raw_pointer_requires_unsafe =
     dereference of raw pointer is unsafe and requires unsafe block
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 58487a48184ad..226c469b7d784 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -702,6 +702,7 @@ pub(crate) struct ConstPatternDependsOnGenericParameter {
 #[diag(mir_build_could_not_eval_const_pattern)]
 pub(crate) struct CouldNotEvalConstPattern {
     #[primary_span]
+    #[label]
     pub(crate) span: Span,
 }
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index aa98874654edd..3690459bf5151 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -122,7 +122,16 @@ impl<'tcx> ConstToPat<'tcx> {
             Ok(Ok(c)) => c,
             Err(ErrorHandled::Reported(_, _)) => {
                 // Let's tell the use where this failing const occurs.
-                let err = self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span });
+                let mut err =
+                    self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span });
+                // We've emitted an error on the original const, it would be redundant to complain
+                // on its use as well.
+                if let ty::ConstKind::Unevaluated(uv) = self.c.kind()
+                    && let hir::def::DefKind::Const | hir::def::DefKind::AssocConst =
+                        self.tcx.def_kind(uv.def)
+                {
+                    err.downgrade_to_delayed_bug();
+                }
                 return self.mk_err(err, ty);
             }
             Err(ErrorHandled::TooGeneric(_)) => {
diff --git a/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.rs b/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.rs
index 09f7e2ba5b1dd..270496d45a6b0 100644
--- a/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.rs
+++ b/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.rs
@@ -12,8 +12,7 @@ impl Opcode2 {
 
 pub fn example2(msg_type: Opcode2) -> impl FnMut(&[u8]) {
     move |i| match msg_type {
-        Opcode2::OP2 => unimplemented!(),
-        //~^ ERROR: could not evaluate constant pattern
+        Opcode2::OP2 => unimplemented!(), // ok, `const` already emitted an error
     }
 }
 
diff --git a/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr b/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr
index 9cce6fee55ac6..d95a8861230e0 100644
--- a/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr
+++ b/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr
@@ -17,18 +17,7 @@ help: you might be missing a type parameter
 LL | pub struct Opcode2<S>(&'a S);
    |                   +++
 
-error: could not evaluate constant pattern
-  --> $DIR/ice-type-mismatch-when-copying-112824.rs:15:9
-   |
-LL | impl Opcode2 {
-   | ------------
-LL |     pub const OP2: Opcode2 = Opcode2(Opcode(0x1));
-   |     ---------------------- constant defined here
-...
-LL |         Opcode2::OP2 => unimplemented!(),
-   |         ^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0261, E0412.
 For more information about an error, try `rustc --explain E0261`.
diff --git a/tests/ui/consts/const-eval/const-eval-overflow-2.rs b/tests/ui/consts/const-eval/const-eval-overflow-2.rs
index c19a0c443ec58..bae8a7ce243e9 100644
--- a/tests/ui/consts/const-eval/const-eval-overflow-2.rs
+++ b/tests/ui/consts/const-eval/const-eval-overflow-2.rs
@@ -12,8 +12,7 @@ const NEG_NEG_128: i8 = -NEG_128; //~ ERROR constant
 
 fn main() {
     match -128i8 {
-        NEG_NEG_128 => println!("A"),
-        //~^ ERROR could not evaluate constant pattern
+        NEG_NEG_128 => println!("A"), // ok, `const` error already emitted
         _ => println!("B"),
     }
 }
diff --git a/tests/ui/consts/const-eval/const-eval-overflow-2.stderr b/tests/ui/consts/const-eval/const-eval-overflow-2.stderr
index 66c54af4f83f6..5599ff931e8e5 100644
--- a/tests/ui/consts/const-eval/const-eval-overflow-2.stderr
+++ b/tests/ui/consts/const-eval/const-eval-overflow-2.stderr
@@ -4,15 +4,6 @@ error[E0080]: evaluation of constant value failed
 LL | const NEG_NEG_128: i8 = -NEG_128;
    |                         ^^^^^^^^ attempt to negate `i8::MIN`, which would overflow
 
-error: could not evaluate constant pattern
-  --> $DIR/const-eval-overflow-2.rs:15:9
-   |
-LL | const NEG_NEG_128: i8 = -NEG_128;
-   | --------------------- constant defined here
-...
-LL |         NEG_NEG_128 => println!("A"),
-   |         ^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr
index b1c6cfd3246e2..18935626af1ca 100644
--- a/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr
+++ b/tests/ui/consts/const-eval/ref_to_int_match.64bit.stderr
@@ -7,15 +7,6 @@ LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
-error: could not evaluate constant pattern
-  --> $DIR/ref_to_int_match.rs:7:14
-   |
-LL |         10..=BAR => {},
-   |              ^^^
-...
-LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
-   | -------------- constant defined here
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/ref_to_int_match.rs b/tests/ui/consts/const-eval/ref_to_int_match.rs
index c627ad97bb05b..be9420e0215d1 100644
--- a/tests/ui/consts/const-eval/ref_to_int_match.rs
+++ b/tests/ui/consts/const-eval/ref_to_int_match.rs
@@ -4,7 +4,7 @@ fn main() {
     let n: Int = 40;
     match n {
         0..=10 => {},
-        10..=BAR => {}, //~ ERROR could not evaluate constant pattern
+        10..=BAR => {}, // ok, `const` error already emitted
         _ => {},
     }
 }
diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.rs b/tests/ui/consts/const_refs_to_static_fail_invalid.rs
index a160862a0fa69..aa101cf9d8a62 100644
--- a/tests/ui/consts/const_refs_to_static_fail_invalid.rs
+++ b/tests/ui/consts/const_refs_to_static_fail_invalid.rs
@@ -11,7 +11,7 @@ fn invalid() {
 
     // This must be rejected here (or earlier), since it's not a valid `&bool`.
     match &true {
-        C => {} //~ERROR: could not evaluate constant pattern
+        C => {} // ok, `const` already emitted an error
         _ => {}
     }
 }
@@ -27,7 +27,7 @@ fn extern_() {
 
     // This must be rejected here (or earlier), since the pattern cannot be read.
     match &0 {
-        C => {} //~ERROR: could not evaluate constant pattern
+        C => {} // ok, `const` already emitted an error
         _ => {}
     }
 }
@@ -42,7 +42,7 @@ fn mutable() {
     // This *must not build*, the constant we are matching against
     // could change its value!
     match &42 {
-        C => {} //~ERROR: could not evaluate constant pattern
+        C => {} // ok, `const` already emitted an error
         _ => {}
     }
 }
diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr
index 9f2633a64d594..c9d5cb60bf779 100644
--- a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr
+++ b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr
@@ -31,33 +31,6 @@ LL |     const C: &i32 = unsafe { &S_MUT };
                HEX_DUMP
            }
 
-error: could not evaluate constant pattern
-  --> $DIR/const_refs_to_static_fail_invalid.rs:14:9
-   |
-LL |     const C: &bool = unsafe { std::mem::transmute(&S) };
-   |     -------------- constant defined here
-...
-LL |         C => {}
-   |         ^
-
-error: could not evaluate constant pattern
-  --> $DIR/const_refs_to_static_fail_invalid.rs:30:9
-   |
-LL |     const C: &i8 = unsafe { &S };
-   |     ------------ constant defined here
-...
-LL |         C => {}
-   |         ^
-
-error: could not evaluate constant pattern
-  --> $DIR/const_refs_to_static_fail_invalid.rs:45:9
-   |
-LL |     const C: &i32 = unsafe { &S_MUT };
-   |     ------------- constant defined here
-...
-LL |         C => {}
-   |         ^
-
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr
index 2e48837bdcdcb..b22f99f40d351 100644
--- a/tests/ui/consts/invalid-inline-const-in-match-arm.stderr
+++ b/tests/ui/consts/invalid-inline-const-in-match-arm.stderr
@@ -11,7 +11,7 @@ error: could not evaluate constant pattern
   --> $DIR/invalid-inline-const-in-match-arm.rs:5:9
    |
 LL |         const { (|| {})() } => {}
-   |         ^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^ could not evaluate constant
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/consts/issue-43105.rs b/tests/ui/consts/issue-43105.rs
index 20b78d64209e1..a4ee34c0532f3 100644
--- a/tests/ui/consts/issue-43105.rs
+++ b/tests/ui/consts/issue-43105.rs
@@ -5,8 +5,7 @@ const NUM: u8 = xyz();
 
 fn main() {
     match 1 {
-        NUM => unimplemented!(),
-        //~^ ERROR could not evaluate constant pattern
+        NUM => unimplemented!(), // ok, the `const` already emitted an error
         _ => unimplemented!(),
     }
 }
diff --git a/tests/ui/consts/issue-43105.stderr b/tests/ui/consts/issue-43105.stderr
index 4c59bdd4520eb..0e08feb58de9b 100644
--- a/tests/ui/consts/issue-43105.stderr
+++ b/tests/ui/consts/issue-43105.stderr
@@ -6,15 +6,6 @@ LL | const NUM: u8 = xyz();
    |
    = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
-error: could not evaluate constant pattern
-  --> $DIR/issue-43105.rs:8:9
-   |
-LL | const NUM: u8 = xyz();
-   | ------------- constant defined here
-...
-LL |         NUM => unimplemented!(),
-   |         ^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/consts/issue-78655.rs b/tests/ui/consts/issue-78655.rs
index cd95ee32c60d2..b0f862e84181a 100644
--- a/tests/ui/consts/issue-78655.rs
+++ b/tests/ui/consts/issue-78655.rs
@@ -4,6 +4,5 @@ const FOO: *const u32 = {
 };
 
 fn main() {
-    let FOO = FOO;
-    //~^ ERROR could not evaluate constant pattern
+    let FOO = FOO; // ok, the `const` already emitted an error
 }
diff --git a/tests/ui/consts/issue-78655.stderr b/tests/ui/consts/issue-78655.stderr
index 5d684227be8bf..6a93c1a8cec91 100644
--- a/tests/ui/consts/issue-78655.stderr
+++ b/tests/ui/consts/issue-78655.stderr
@@ -11,15 +11,6 @@ help: consider assigning a value
 LL |     let x = 42;
    |           ++++
 
-error: could not evaluate constant pattern
-  --> $DIR/issue-78655.rs:7:9
-   |
-LL | const FOO: *const u32 = {
-   | --------------------- constant defined here
-...
-LL |     let FOO = FOO;
-   |         ^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs
index a6d75658c7580..facb21a04ef0b 100644
--- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs
+++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs
@@ -37,16 +37,14 @@ const U8_MUT3: &u8 = {
 
 pub fn test(x: &[u8; 1]) -> bool {
     match x {
-        SLICE_MUT => true,
-        //~^ ERROR could not evaluate constant pattern
+        SLICE_MUT => true, // ok, `const` error already emitted
         &[1..] => false,
     }
 }
 
 pub fn test2(x: &u8) -> bool {
     match x {
-        U8_MUT => true,
-        //~^ ERROR could not evaluate constant pattern
+        U8_MUT => true, // ok, `const` error already emitted
         &(1..) => false,
     }
 }
@@ -55,15 +53,13 @@ pub fn test2(x: &u8) -> bool {
 // the errors above otherwise stop compilation too early?
 pub fn test3(x: &u8) -> bool {
     match x {
-        U8_MUT2 => true,
-        //~^ ERROR could not evaluate constant pattern
+        U8_MUT2 => true, // ok, `const` error already emitted
         &(1..) => false,
     }
 }
 pub fn test4(x: &u8) -> bool {
     match x {
-        U8_MUT3 => true,
-        //~^ ERROR could not evaluate constant pattern
+        U8_MUT3 => true, // ok, `const` error already emitted
         &(1..) => false,
     }
 }
diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr
index 513f456bdf4e6..8f8271cce38e9 100644
--- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr
+++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr
@@ -37,42 +37,6 @@ error[E0080]: evaluation of constant value failed
 LL |         match static_cross_crate::OPT_ZERO {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses mutable global memory
 
-error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:40:9
-   |
-LL | const SLICE_MUT: &[u8; 1] = {
-   | ------------------------- constant defined here
-...
-LL |         SLICE_MUT => true,
-   |         ^^^^^^^^^
-
-error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:48:9
-   |
-LL | const U8_MUT: &u8 = {
-   | ----------------- constant defined here
-...
-LL |         U8_MUT => true,
-   |         ^^^^^^
-
-error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:58:9
-   |
-LL | const U8_MUT2: &u8 = {
-   | ------------------ constant defined here
-...
-LL |         U8_MUT2 => true,
-   |         ^^^^^^^
-
-error: could not evaluate constant pattern
-  --> $DIR/const_refers_to_static_cross_crate.rs:65:9
-   |
-LL | const U8_MUT3: &u8 = {
-   | ------------------ constant defined here
-...
-LL |         U8_MUT3 => true,
-   |         ^^^^^^^
-
-error: aborting due to 8 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/missing_assoc_const_type.rs b/tests/ui/consts/missing_assoc_const_type.rs
index 633998e9bc157..61042bfa96d08 100644
--- a/tests/ui/consts/missing_assoc_const_type.rs
+++ b/tests/ui/consts/missing_assoc_const_type.rs
@@ -9,14 +9,13 @@ trait Range {
 
 struct TwoDigits;
 impl Range for TwoDigits {
-    const FIRST:  = 10;
-    //~^ ERROR: missing type for `const` item
+    const FIRST:  = 10; //~ ERROR missing type for `const` item
     const LAST: u8 = 99;
 }
 
 const fn digits(x: u8) -> usize {
     match x {
-        TwoDigits::FIRST..=TwoDigits::LAST => 0, //~ ERROR: could not evaluate constant pattern
+        TwoDigits::FIRST..=TwoDigits::LAST => 0, // ok, `const` error already emitted
         0..=9 | 100..=255 => panic!(),
     }
 }
diff --git a/tests/ui/consts/missing_assoc_const_type.stderr b/tests/ui/consts/missing_assoc_const_type.stderr
index 8123a43ef74fe..28af1f0f321e6 100644
--- a/tests/ui/consts/missing_assoc_const_type.stderr
+++ b/tests/ui/consts/missing_assoc_const_type.stderr
@@ -4,16 +4,5 @@ error: missing type for `const` item
 LL |     const FIRST:  = 10;
    |                 ^ help: provide a type for the associated constant: `u8`
 
-error: could not evaluate constant pattern
-  --> $DIR/missing_assoc_const_type.rs:19:9
-   |
-LL | trait Range {
-   | -----------
-LL |     const FIRST: u8;
-   |     --------------- constant defined here
-...
-LL |         TwoDigits::FIRST..=TwoDigits::LAST => 0,
-   |         ^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/transmute-size-mismatch-before-typeck.rs b/tests/ui/consts/transmute-size-mismatch-before-typeck.rs
index 44eac5b16cc0b..ffb143da2d48b 100644
--- a/tests/ui/consts/transmute-size-mismatch-before-typeck.rs
+++ b/tests/ui/consts/transmute-size-mismatch-before-typeck.rs
@@ -5,7 +5,7 @@
 
 fn main() {
     match &b""[..] {
-        ZST => {} //~ ERROR: could not evaluate constant pattern
+        ZST => {} // ok, `const` error already emitted
     }
 }
 
diff --git a/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr b/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr
index 79f59ba865d8d..6bc7e7203aa74 100644
--- a/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr
+++ b/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr
@@ -7,15 +7,6 @@ LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
    = note: source type: `usize` (word size)
    = note: target type: `&[u8]` (2 * word size)
 
-error: could not evaluate constant pattern
-  --> $DIR/transmute-size-mismatch-before-typeck.rs:8:9
-   |
-LL |         ZST => {}
-   |         ^^^
-...
-LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
-   | ---------------- constant defined here
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0512`.

From c0f00086f85ae1fff34dd2daf6a11850e5bfc2f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 20 Nov 2024 03:00:58 +0000
Subject: [PATCH 10/21] Tweak ptr in pattern error

Conform to error style guide.
---
 compiler/rustc_mir_build/messages.ftl         |  4 +-
 compiler/rustc_mir_build/src/errors.rs        |  2 +
 src/tools/tidy/src/fluent_period.rs           |  1 -
 ...ssue-34784-match-on-non-int-raw-ptr.stderr | 24 +++++---
 .../const_in_pattern/issue-44333.stderr       | 12 ++--
 .../pattern/usefulness/consts-opaque.stderr   | 48 ++++++++++-----
 ...n-ptr-is-not-structurally-matchable.stderr | 60 ++++++++++++-------
 .../issue-63479-match-fnptr.stderr            | 12 ++--
 8 files changed, 109 insertions(+), 54 deletions(-)

diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index ad2f13f6d21ab..2bf49137e8f8c 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -274,7 +274,9 @@ mir_build_non_partial_eq_match =
 mir_build_pattern_not_covered = refutable pattern in {$origin}
     .pattern_ty = the matched value is of type `{$pattern_ty}`
 
-mir_build_pointer_pattern = function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+mir_build_pointer_pattern = function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
+    .label = can't be used in patterns
+    .note = see https://github.com/rust-lang/rust/issues/70861 for details
 
 mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
 
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 226c469b7d784..7f4bb139fad2c 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -916,8 +916,10 @@ pub(crate) struct NaNPattern {
 
 #[derive(Diagnostic)]
 #[diag(mir_build_pointer_pattern)]
+#[note]
 pub(crate) struct PointerPattern {
     #[primary_span]
+    #[label]
     pub(crate) span: Span,
 }
 
diff --git a/src/tools/tidy/src/fluent_period.rs b/src/tools/tidy/src/fluent_period.rs
index 8bc404dc8581a..6a136e5aec698 100644
--- a/src/tools/tidy/src/fluent_period.rs
+++ b/src/tools/tidy/src/fluent_period.rs
@@ -18,7 +18,6 @@ const ALLOWLIST: &[&str] = &[
     "const_eval_validation_failure_note",
     "driver_impl_ice",
     "incremental_corrupt_file",
-    "mir_build_pointer_pattern",
 ];
 
 fn check_period(filename: &str, contents: &str, bad: &mut bool) {
diff --git a/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr b/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr
index cc7ec771e6cd6..0453a88e43db9 100644
--- a/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr
+++ b/tests/ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.stderr
@@ -1,38 +1,46 @@
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:9:9
    |
 LL | const C: *const u8 = &0;
    | ------------------ constant defined here
 ...
 LL |         C => {}
-   |         ^
+   |         ^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:16:9
    |
 LL | const C_INNER: (*const u8, u8) = (C, 0);
    | ------------------------------ constant defined here
 ...
 LL |         C_INNER => {}
-   |         ^^^^^^^
+   |         ^^^^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:27:9
    |
 LL | const D: *const [u8; 4] = b"abcd";
    | ----------------------- constant defined here
 ...
 LL |         D => {}
-   |         ^
+   |         ^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/issue-34784-match-on-non-int-raw-ptr.rs:32:9
    |
 LL | const STR: *const str = "abcd";
    | --------------------- constant defined here
 ...
 LL |         STR => {}
-   |         ^^^
+   |         ^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/consts/const_in_pattern/issue-44333.stderr b/tests/ui/consts/const_in_pattern/issue-44333.stderr
index 81393952f0fcf..61b45377c7610 100644
--- a/tests/ui/consts/const_in_pattern/issue-44333.stderr
+++ b/tests/ui/consts/const_in_pattern/issue-44333.stderr
@@ -1,20 +1,24 @@
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/issue-44333.rs:15:9
    |
 LL | const FOO: Func = foo;
    | --------------- constant defined here
 ...
 LL |         FOO => println!("foo"),
-   |         ^^^
+   |         ^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/issue-44333.rs:16:9
    |
 LL | const BAR: Func = bar;
    | --------------- constant defined here
 ...
 LL |         BAR => println!("bar"),
-   |         ^^^
+   |         ^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr
index 15aa1769662cd..d52451d9438a1 100644
--- a/tests/ui/pattern/usefulness/consts-opaque.stderr
+++ b/tests/ui/pattern/usefulness/consts-opaque.stderr
@@ -1,74 +1,90 @@
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/consts-opaque.rs:96:9
    |
 LL |     const QUUX: Quux = quux;
    |     ---------------- constant defined here
 ...
 LL |         QUUX => {}
-   |         ^^^^
+   |         ^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/consts-opaque.rs:97:9
    |
 LL |     const QUUX: Quux = quux;
    |     ---------------- constant defined here
 ...
 LL |         QUUX => {}
-   |         ^^^^
+   |         ^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/consts-opaque.rs:106:9
    |
 LL |     const WRAPQUUX: Wrap<Quux> = Wrap(quux);
    |     -------------------------- constant defined here
 ...
 LL |         WRAPQUUX => {}
-   |         ^^^^^^^^
+   |         ^^^^^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/consts-opaque.rs:107:9
    |
 LL |     const WRAPQUUX: Wrap<Quux> = Wrap(quux);
    |     -------------------------- constant defined here
 ...
 LL |         WRAPQUUX => {}
-   |         ^^^^^^^^
+   |         ^^^^^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/consts-opaque.rs:113:9
    |
 LL |     const WRAPQUUX: Wrap<Quux> = Wrap(quux);
    |     -------------------------- constant defined here
 ...
 LL |         WRAPQUUX => {}
-   |         ^^^^^^^^
+   |         ^^^^^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/consts-opaque.rs:121:9
    |
 LL |     const WRAPQUUX: Wrap<Quux> = Wrap(quux);
    |     -------------------------- constant defined here
 ...
 LL |         WRAPQUUX => {}
-   |         ^^^^^^^^
+   |         ^^^^^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/consts-opaque.rs:132:9
    |
 LL |     const WHOKNOWSQUUX: WhoKnows<Quux> = WhoKnows::Yay(quux);
    |     ---------------------------------- constant defined here
 ...
 LL |         WHOKNOWSQUUX => {}
-   |         ^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/consts-opaque.rs:134:9
    |
 LL |     const WHOKNOWSQUUX: WhoKnows<Quux> = WhoKnows::Yay(quux);
    |     ---------------------------------- constant defined here
 ...
 LL |         WHOKNOWSQUUX => {}
-   |         ^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
 error: unreachable pattern
   --> $DIR/consts-opaque.rs:48:9
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-not-structurally-matchable.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-not-structurally-matchable.stderr
index ee6f44a364da4..cdbe72ca48f8f 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-not-structurally-matchable.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/fn-ptr-is-not-structurally-matchable.stderr
@@ -1,92 +1,112 @@
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:41:14
    |
 LL |     const CFN1: Wrap<fn()> = Wrap(trivial);
    |     ---------------------- constant defined here
 ...
 LL |         Wrap(CFN1) => count += 1,
-   |              ^^^^
+   |              ^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:49:14
    |
 LL |     const CFN2: Wrap<fn(SM)> = Wrap(sm_to);
    |     ------------------------ constant defined here
 ...
 LL |         Wrap(CFN2) => count += 1,
-   |              ^^^^
+   |              ^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:57:14
    |
 LL |     const CFN3: Wrap<fn() -> SM> = Wrap(to_sm);
    |     ---------------------------- constant defined here
 ...
 LL |         Wrap(CFN3) => count += 1,
-   |              ^^^^
+   |              ^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:65:14
    |
 LL |     const CFN4: Wrap<fn(NotSM)> = Wrap(not_sm_to);
    |     --------------------------- constant defined here
 ...
 LL |         Wrap(CFN4) => count += 1,
-   |              ^^^^
+   |              ^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:73:14
    |
 LL |     const CFN5: Wrap<fn() -> NotSM> = Wrap(to_not_sm);
    |     ------------------------------- constant defined here
 ...
 LL |         Wrap(CFN5) => count += 1,
-   |              ^^^^
+   |              ^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:81:14
    |
 LL |     const CFN6: Wrap<fn(&SM)> = Wrap(r_sm_to);
    |     ------------------------- constant defined here
 ...
 LL |         Wrap(CFN6) => count += 1,
-   |              ^^^^
+   |              ^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:89:14
    |
 LL |     const CFN7: Wrap<fn(&()) -> &SM> = Wrap(r_to_r_sm);
    |     -------------------------------- constant defined here
 ...
 LL |         Wrap(CFN7) => count += 1,
-   |              ^^^^
+   |              ^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:97:14
    |
 LL |     const CFN8: Wrap<fn(&NotSM)> = Wrap(r_not_sm_to);
    |     ---------------------------- constant defined here
 ...
 LL |         Wrap(CFN8) => count += 1,
-   |              ^^^^
+   |              ^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:105:14
    |
 LL |     const CFN9: Wrap<fn(&()) -> &NotSM> = Wrap(r_to_r_not_sm);
    |     ----------------------------------- constant defined here
 ...
 LL |         Wrap(CFN9) => count += 1,
-   |              ^^^^
+   |              ^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/fn-ptr-is-not-structurally-matchable.rs:127:9
    |
 LL |     const CFOO: Foo = Foo {
    |     --------------- constant defined here
 ...
 LL |         CFOO => count += 1,
-   |         ^^^^
+   |         ^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
 error: aborting due to 10 previous errors
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr
index be735ccab0a5a..ea6121839be5e 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.stderr
@@ -1,20 +1,24 @@
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/issue-63479-match-fnptr.rs:32:7
    |
 LL | const TEST: Fn = my_fn;
    | -------------- constant defined here
 ...
 LL |     B(TEST) => println!("matched"),
-   |       ^^^^
+   |       ^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
-error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+error: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon
   --> $DIR/issue-63479-match-fnptr.rs:37:5
    |
 LL | const TEST2: (Fn, u8) = (TEST, 0);
    | --------------------- constant defined here
 ...
 LL |     TEST2 => println!("matched"),
-   |     ^^^^^
+   |     ^^^^^ can't be used in patterns
+   |
+   = note: see https://github.com/rust-lang/rust/issues/70861 for details
 
 error: aborting due to 2 previous errors
 

From 87ddc1ea33edbe1be119d73e57c2783940e797fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 20 Nov 2024 03:08:52 +0000
Subject: [PATCH 11/21] Point at generic param through which a const is used in
 a pattern

```
error[E0158]: constant pattern depends on a generic parameter, which is not allowed
  --> $DIR/associated-const-type-parameter-pattern.rs:20:9
   |
LL | pub trait Foo {
   | -------------
LL |     const X: EFoo;
   |     ------------- constant defined here
...
LL | pub fn test<A: Foo, B: Foo>(arg: EFoo) {
   |             - constant depends on this generic param
LL |     match arg {
LL |         A::X => println!("A::X"),
   |         ^^^^ `const` depends on a generic parameter
```
---
 compiler/rustc_mir_build/messages.ftl         |  4 +--
 compiler/rustc_mir_build/src/errors.rs        |  1 +
 .../src/thir/pattern/const_to_pat.rs          | 22 ++++++++++++++-
 ...ciated-const-type-parameter-pattern.stderr | 27 +++++++++++++------
 .../ui/consts/issue-73976-polymorphic.stderr  | 12 ++++++---
 tests/ui/consts/issue-79137-toogeneric.stderr |  6 +++--
 .../const-match-pat-generic.stderr            |  8 +++---
 7 files changed, 59 insertions(+), 21 deletions(-)

diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 2bf49137e8f8c..4bc7dcf956467 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -88,8 +88,8 @@ mir_build_const_defined_here = constant defined here
 
 mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns
 
-mir_build_const_pattern_depends_on_generic_parameter =
-    constant pattern depends on a generic parameter
+mir_build_const_pattern_depends_on_generic_parameter = constant pattern depends on a generic parameter, which is not allowed
+    .label = `const` depends on a generic parameter
 
 mir_build_could_not_eval_const_pattern = could not evaluate constant pattern
     .label = could not evaluate constant
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 7f4bb139fad2c..1068c56eeca61 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -695,6 +695,7 @@ pub(crate) struct WantedConstant {
 #[diag(mir_build_const_pattern_depends_on_generic_parameter, code = E0158)]
 pub(crate) struct ConstPatternDependsOnGenericParameter {
     #[primary_span]
+    #[label]
     pub(crate) span: Span,
 }
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 3690459bf5151..b625c655fac42 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -53,6 +53,7 @@ struct ConstToPat<'tcx> {
     tcx: TyCtxt<'tcx>,
     typing_env: ty::TypingEnv<'tcx>,
     span: Span,
+    id: hir::HirId,
 
     treat_byte_string_as_slice: bool,
 
@@ -66,6 +67,7 @@ impl<'tcx> ConstToPat<'tcx> {
             tcx: pat_ctxt.tcx,
             typing_env: pat_ctxt.typing_env,
             span,
+            id,
             treat_byte_string_as_slice: pat_ctxt
                 .typeck_results
                 .treat_byte_string_as_slice
@@ -135,10 +137,28 @@ impl<'tcx> ConstToPat<'tcx> {
                 return self.mk_err(err, ty);
             }
             Err(ErrorHandled::TooGeneric(_)) => {
-                let e = self
+                let mut e = self
                     .tcx
                     .dcx()
                     .create_err(ConstPatternDependsOnGenericParameter { span: self.span });
+                for arg in uv.args {
+                    if let ty::GenericArgKind::Type(ty) = arg.unpack()
+                        && let ty::Param(param_ty) = ty.kind()
+                    {
+                        let def_id = self.tcx.hir().enclosing_body_owner(self.id);
+                        let generics = self.tcx.generics_of(def_id);
+                        let param = generics.type_param(*param_ty, self.tcx);
+                        let span = self.tcx.def_span(param.def_id);
+                        e.span_label(span, "constant depends on this generic param");
+                        if let Some(ident) = self.tcx.def_ident_span(def_id)
+                            && self.tcx.sess.source_map().is_multiline(ident.between(span))
+                        {
+                            // Display the `fn` name as well in the diagnostic, as the generic isn't
+                            // in the same line and it could be confusing otherwise.
+                            e.span_label(ident, "");
+                        }
+                    }
+                }
                 return self.mk_err(e, ty);
             }
             Ok(Err(bad_ty)) => {
diff --git a/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr b/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr
index 5aef0fa414bd4..455831e8401cb 100644
--- a/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr
+++ b/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr
@@ -1,4 +1,4 @@
-error[E0158]: constant pattern depends on a generic parameter
+error[E0158]: constant pattern depends on a generic parameter, which is not allowed
   --> $DIR/associated-const-type-parameter-pattern.rs:20:9
    |
 LL | pub trait Foo {
@@ -6,10 +6,13 @@ LL | pub trait Foo {
 LL |     const X: EFoo;
    |     ------------- constant defined here
 ...
+LL | pub fn test<A: Foo, B: Foo>(arg: EFoo) {
+   |             - constant depends on this generic param
+LL |     match arg {
 LL |         A::X => println!("A::X"),
-   |         ^^^^
+   |         ^^^^ `const` depends on a generic parameter
 
-error[E0158]: constant pattern depends on a generic parameter
+error[E0158]: constant pattern depends on a generic parameter, which is not allowed
   --> $DIR/associated-const-type-parameter-pattern.rs:22:9
    |
 LL | pub trait Foo {
@@ -17,10 +20,13 @@ LL | pub trait Foo {
 LL |     const X: EFoo;
    |     ------------- constant defined here
 ...
+LL | pub fn test<A: Foo, B: Foo>(arg: EFoo) {
+   |                     - constant depends on this generic param
+...
 LL |         B::X => println!("B::X"),
-   |         ^^^^
+   |         ^^^^ `const` depends on a generic parameter
 
-error[E0158]: constant pattern depends on a generic parameter
+error[E0158]: constant pattern depends on a generic parameter, which is not allowed
   --> $DIR/associated-const-type-parameter-pattern.rs:30:9
    |
 LL | pub trait Foo {
@@ -28,10 +34,13 @@ LL | pub trait Foo {
 LL |     const X: EFoo;
    |     ------------- constant defined here
 ...
+LL | pub fn test_let_pat<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
+   |                     - constant depends on this generic param
+LL |
 LL |     let A::X = arg;
-   |         ^^^^
+   |         ^^^^ `const` depends on a generic parameter
 
-error[E0158]: constant pattern depends on a generic parameter
+error[E0158]: constant pattern depends on a generic parameter, which is not allowed
   --> $DIR/associated-const-type-parameter-pattern.rs:28:48
    |
 LL | pub trait Foo {
@@ -40,7 +49,9 @@ LL |     const X: EFoo;
    |     ------------- constant defined here
 ...
 LL | pub fn test_let_pat<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
-   |                                                ^^^^
+   |                     -                          ^^^^ `const` depends on a generic parameter
+   |                     |
+   |                     constant depends on this generic param
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/consts/issue-73976-polymorphic.stderr b/tests/ui/consts/issue-73976-polymorphic.stderr
index 79a03d4ec32c9..2f50e6ac2fd42 100644
--- a/tests/ui/consts/issue-73976-polymorphic.stderr
+++ b/tests/ui/consts/issue-73976-polymorphic.stderr
@@ -1,4 +1,4 @@
-error[E0158]: constant pattern depends on a generic parameter
+error[E0158]: constant pattern depends on a generic parameter, which is not allowed
   --> $DIR/issue-73976-polymorphic.rs:20:37
    |
 LL | impl<T: 'static> GetTypeId<T> {
@@ -6,10 +6,12 @@ LL | impl<T: 'static> GetTypeId<T> {
 LL |     pub const VALUE: TypeId = TypeId::of::<T>();
    |     ----------------------- constant defined here
 ...
+LL | const fn check_type_id<T: 'static>() -> bool {
+   |                        - constant depends on this generic param
 LL |     matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
-   |                                     ^^^^^^^^^^^^^^^^^^^^^
+   |                                     ^^^^^^^^^^^^^^^^^^^^^ `const` depends on a generic parameter
 
-error[E0158]: constant pattern depends on a generic parameter
+error[E0158]: constant pattern depends on a generic parameter, which is not allowed
   --> $DIR/issue-73976-polymorphic.rs:31:42
    |
 LL | impl<T: 'static> GetTypeNameLen<T> {
@@ -17,8 +19,10 @@ LL | impl<T: 'static> GetTypeNameLen<T> {
 LL |     pub const VALUE: usize = any::type_name::<T>().len();
    |     ---------------------- constant defined here
 ...
+LL | const fn check_type_name_len<T: 'static>() -> bool {
+   |                              - constant depends on this generic param
 LL |     matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
-   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^ `const` depends on a generic parameter
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/consts/issue-79137-toogeneric.stderr b/tests/ui/consts/issue-79137-toogeneric.stderr
index 9b53a2595479d..d36f3ecbb7690 100644
--- a/tests/ui/consts/issue-79137-toogeneric.stderr
+++ b/tests/ui/consts/issue-79137-toogeneric.stderr
@@ -1,4 +1,4 @@
-error[E0158]: constant pattern depends on a generic parameter
+error[E0158]: constant pattern depends on a generic parameter, which is not allowed
   --> $DIR/issue-79137-toogeneric.rs:12:43
    |
 LL | impl<T> GetVariantCount<T> {
@@ -6,8 +6,10 @@ LL | impl<T> GetVariantCount<T> {
 LL |     pub const VALUE: usize = std::mem::variant_count::<T>();
    |     ---------------------- constant defined here
 ...
+LL | const fn check_variant_count<T>() -> bool {
+   |                              - constant depends on this generic param
 LL |     matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE)
-   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `const` depends on a generic parameter
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/inline-const/const-match-pat-generic.stderr b/tests/ui/inline-const/const-match-pat-generic.stderr
index 26f72b34eca29..cf48161b5e3d6 100644
--- a/tests/ui/inline-const/const-match-pat-generic.stderr
+++ b/tests/ui/inline-const/const-match-pat-generic.stderr
@@ -1,14 +1,14 @@
-error[E0158]: constant pattern depends on a generic parameter
+error[E0158]: constant pattern depends on a generic parameter, which is not allowed
   --> $DIR/const-match-pat-generic.rs:7:9
    |
 LL |         const { V } => {},
-   |         ^^^^^^^^^^^
+   |         ^^^^^^^^^^^ `const` depends on a generic parameter
 
-error[E0158]: constant pattern depends on a generic parameter
+error[E0158]: constant pattern depends on a generic parameter, which is not allowed
   --> $DIR/const-match-pat-generic.rs:19:9
    |
 LL |         const { f(V) } => {},
-   |         ^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^ `const` depends on a generic parameter
 
 error: aborting due to 2 previous errors
 

From 253eb95d4582e1abffc4a74dd8eaccd5b94b5d6f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 20 Nov 2024 03:57:30 +0000
Subject: [PATCH 12/21] Tweak output of some const pattern errors

- Add primary span labels.
- Point at const generic parameter used as pattern.
- Point at statics used as pattern.
- Point at let bindings used in const pattern.
---
 compiler/rustc_mir_build/messages.ftl              | 10 +++++++++-
 compiler/rustc_mir_build/src/errors.rs             | 10 ++++++++++
 compiler/rustc_mir_build/src/thir/pattern/mod.rs   | 14 ++++++++++----
 tests/ui/binding/const-param.rs                    |  2 +-
 tests/ui/binding/const-param.stderr                |  7 +++++--
 .../ui/consts/const_in_pattern/issue-65466.stderr  |  2 +-
 .../const_in_pattern/reject_non_partial_eq.stderr  |  2 +-
 .../match/issue-72896-non-partial-eq-const.stderr  |  2 +-
 tests/ui/pattern/non-constant-in-const-path.stderr | 14 ++++++++++----
 ...e-61188-match-slice-forbidden-without-eq.stderr |  2 +-
 .../issue-6804-nan-match.stderr                    | 14 +++++++-------
 tests/ui/union/union-const-pat.stderr              |  2 +-
 12 files changed, 57 insertions(+), 24 deletions(-)

diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 4bc7dcf956467..28011833e5869 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -86,7 +86,9 @@ mir_build_confused = missing patterns are not covered because `{$variable}` is i
 
 mir_build_const_defined_here = constant defined here
 
-mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns
+mir_build_const_param_in_pattern = constant parameters cannot be referenced in patterns
+    .label = can't be used in patterns
+mir_build_const_param_in_pattern_def = constant defined here
 
 mir_build_const_pattern_depends_on_generic_parameter = constant pattern depends on a generic parameter, which is not allowed
     .label = `const` depends on a generic parameter
@@ -247,10 +249,12 @@ mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsa
     .label = mutation of layout constrained field
 
 mir_build_nan_pattern = cannot use NaN in patterns
+    .label = evaluates to `NaN`, which is not allowed in patterns
     .note = NaNs compare inequal to everything, even themselves, so this pattern would never match
     .help = try using the `is_nan` method instead
 
 mir_build_non_const_path = runtime values cannot be referenced in patterns
+    .label = references a runtime value
 
 mir_build_non_empty_never_pattern =
     mismatched types
@@ -270,6 +274,7 @@ mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type
 
 mir_build_non_partial_eq_match =
     to use a constant of type `{$non_peq_ty}` in a pattern, the type must implement `PartialEq`
+    .label = constant of non-structural type
 
 mir_build_pattern_not_covered = refutable pattern in {$origin}
     .pattern_ty = the matched value is of type `{$pattern_ty}`
@@ -288,6 +293,8 @@ mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
     .missing_box = `#[rustc_box]` requires the `owned_box` lang item
 
 mir_build_static_in_pattern = statics cannot be referenced in patterns
+    .label = can't be used in patterns
+mir_build_static_in_pattern_def = `static` defined here
 
 mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
 
@@ -339,6 +346,7 @@ mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
     .label = access to union field
 
 mir_build_union_pattern = cannot use unions in constant patterns
+    .label = can't use a `union` here
 
 mir_build_unreachable_making_this_unreachable = collectively making this unreachable
 
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 1068c56eeca61..1c4de5c07a13e 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -631,20 +631,27 @@ pub(crate) struct NonExhaustiveMatchAllArmsGuarded;
 #[diag(mir_build_static_in_pattern, code = E0158)]
 pub(crate) struct StaticInPattern {
     #[primary_span]
+    #[label]
     pub(crate) span: Span,
+    #[label(mir_build_static_in_pattern_def)]
+    pub(crate) static_span: Span,
 }
 
 #[derive(Diagnostic)]
 #[diag(mir_build_const_param_in_pattern, code = E0158)]
 pub(crate) struct ConstParamInPattern {
     #[primary_span]
+    #[label]
     pub(crate) span: Span,
+    #[label(mir_build_const_param_in_pattern_def)]
+    pub(crate) const_span: Span,
 }
 
 #[derive(Diagnostic)]
 #[diag(mir_build_non_const_path, code = E0080)]
 pub(crate) struct NonConstPath {
     #[primary_span]
+    #[label]
     pub(crate) span: Span,
 }
 
@@ -869,6 +876,7 @@ pub(crate) enum Conflict {
 #[diag(mir_build_union_pattern)]
 pub(crate) struct UnionPattern {
     #[primary_span]
+    #[label]
     pub(crate) span: Span,
 }
 
@@ -886,6 +894,7 @@ pub(crate) struct TypeNotStructural<'tcx> {
 #[diag(mir_build_non_partial_eq_match)]
 pub(crate) struct TypeNotPartialEq<'tcx> {
     #[primary_span]
+    #[label]
     pub(crate) span: Span,
     pub(crate) non_peq_ty: Ty<'tcx>,
 }
@@ -912,6 +921,7 @@ pub(crate) struct UnsizedPattern<'tcx> {
 #[help]
 pub(crate) struct NaNPattern {
     #[primary_span]
+    #[label]
     pub(crate) span: Span,
 }
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 08c6b4abd3b91..3ac53fa6272be 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -528,11 +528,17 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             | Res::SelfCtor(..) => PatKind::Leaf { subpatterns },
             _ => {
                 let e = match res {
-                    Res::Def(DefKind::ConstParam, _) => {
-                        self.tcx.dcx().emit_err(ConstParamInPattern { span })
+                    Res::Def(DefKind::ConstParam, def_id) => {
+                        self.tcx.dcx().emit_err(ConstParamInPattern {
+                            span,
+                            const_span: self.tcx().def_span(def_id),
+                        })
                     }
-                    Res::Def(DefKind::Static { .. }, _) => {
-                        self.tcx.dcx().emit_err(StaticInPattern { span })
+                    Res::Def(DefKind::Static { .. }, def_id) => {
+                        self.tcx.dcx().emit_err(StaticInPattern {
+                            span,
+                            static_span: self.tcx().def_span(def_id),
+                        })
                     }
                     _ => self.tcx.dcx().emit_err(NonConstPath { span }),
                 };
diff --git a/tests/ui/binding/const-param.rs b/tests/ui/binding/const-param.rs
index 2d051808fe0be..98bc90f508ab2 100644
--- a/tests/ui/binding/const-param.rs
+++ b/tests/ui/binding/const-param.rs
@@ -2,7 +2,7 @@
 
 fn check<const N: usize>() {
     match 1 {
-        N => {} //~ ERROR const parameters cannot be referenced in patterns
+        N => {} //~ ERROR constant parameters cannot be referenced in patterns
         _ => {}
     }
 }
diff --git a/tests/ui/binding/const-param.stderr b/tests/ui/binding/const-param.stderr
index e68893a59e499..b0b8108945c98 100644
--- a/tests/ui/binding/const-param.stderr
+++ b/tests/ui/binding/const-param.stderr
@@ -1,8 +1,11 @@
-error[E0158]: const parameters cannot be referenced in patterns
+error[E0158]: constant parameters cannot be referenced in patterns
   --> $DIR/const-param.rs:5:9
    |
+LL | fn check<const N: usize>() {
+   |          -------------- constant defined here
+LL |     match 1 {
 LL |         N => {}
-   |         ^
+   |         ^ can't be used in patterns
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/const_in_pattern/issue-65466.stderr b/tests/ui/consts/const_in_pattern/issue-65466.stderr
index 070ce384f6aad..90bac6262cc9d 100644
--- a/tests/ui/consts/const_in_pattern/issue-65466.stderr
+++ b/tests/ui/consts/const_in_pattern/issue-65466.stderr
@@ -5,7 +5,7 @@ LL | const C: &[O<B>] = &[O::None];
    | ---------------- constant defined here
 ...
 LL |         C => (),
-   |         ^
+   |         ^ constant of non-structural type
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
index 463b37e7caa73..d4952a8bfb8c6 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
+++ b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
@@ -5,7 +5,7 @@ LL | const NO_PARTIAL_EQ_NONE: Option<NoPartialEq> = None;
    | --------------------------------------------- constant defined here
 ...
 LL |         NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"),
-   |         ^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^ constant of non-structural type
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/match/issue-72896-non-partial-eq-const.stderr b/tests/ui/match/issue-72896-non-partial-eq-const.stderr
index eeca541fc3cd8..d6ae9e56377d5 100644
--- a/tests/ui/match/issue-72896-non-partial-eq-const.stderr
+++ b/tests/ui/match/issue-72896-non-partial-eq-const.stderr
@@ -5,7 +5,7 @@ LL | const CONST_SET: EnumSet<Enum8> = EnumSet { __enumset_underlying: 3 };
    | ------------------------------- constant defined here
 ...
 LL |         CONST_SET => { /* ok */ }
-   |         ^^^^^^^^^
+   |         ^^^^^^^^^ constant of non-structural type
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/pattern/non-constant-in-const-path.stderr b/tests/ui/pattern/non-constant-in-const-path.stderr
index 53c3974f780e4..2ba4963e6dc2d 100644
--- a/tests/ui/pattern/non-constant-in-const-path.stderr
+++ b/tests/ui/pattern/non-constant-in-const-path.stderr
@@ -2,25 +2,31 @@ error[E0080]: runtime values cannot be referenced in patterns
   --> $DIR/non-constant-in-const-path.rs:8:15
    |
 LL |     let 0u8..=x = 0;
-   |               ^
+   |               ^ references a runtime value
 
 error[E0158]: statics cannot be referenced in patterns
   --> $DIR/non-constant-in-const-path.rs:10:15
    |
+LL | static FOO: u8 = 10;
+   | -------------- `static` defined here
+...
 LL |     let 0u8..=FOO = 0;
-   |               ^^^
+   |               ^^^ can't be used in patterns
 
 error[E0080]: runtime values cannot be referenced in patterns
   --> $DIR/non-constant-in-const-path.rs:13:15
    |
 LL |         0 ..= x => {}
-   |               ^
+   |               ^ references a runtime value
 
 error[E0158]: statics cannot be referenced in patterns
   --> $DIR/non-constant-in-const-path.rs:15:15
    |
+LL | static FOO: u8 = 10;
+   | -------------- `static` defined here
+...
 LL |         0 ..= FOO => {}
-   |               ^^^
+   |               ^^^ can't be used in patterns
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
index e105c6a1f98a9..51bcfc07c9e01 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
@@ -5,7 +5,7 @@ LL | const A: &[B] = &[];
    | ------------- constant defined here
 ...
 LL |         A => (),
-   |         ^
+   |         ^ constant of non-structural type
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr
index 4e2dcb52da807..7c49870e5d03d 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.stderr
@@ -5,7 +5,7 @@ LL | const NAN: f64 = f64::NAN;
    | -------------- constant defined here
 ...
 LL |         NAN => {},
-   |         ^^^
+   |         ^^^ evaluates to `NaN`, which is not allowed in patterns
    |
    = note: NaNs compare inequal to everything, even themselves, so this pattern would never match
    = help: try using the `is_nan` method instead
@@ -17,7 +17,7 @@ LL | const NAN: f64 = f64::NAN;
    | -------------- constant defined here
 ...
 LL |         [NAN, _] => {},
-   |          ^^^
+   |          ^^^ evaluates to `NaN`, which is not allowed in patterns
    |
    = note: NaNs compare inequal to everything, even themselves, so this pattern would never match
    = help: try using the `is_nan` method instead
@@ -29,7 +29,7 @@ LL | const C: MyType<f32> = MyType(f32::NAN);
    | -------------------- constant defined here
 ...
 LL |         C => {},
-   |         ^
+   |         ^ evaluates to `NaN`, which is not allowed in patterns
    |
    = note: NaNs compare inequal to everything, even themselves, so this pattern would never match
    = help: try using the `is_nan` method instead
@@ -41,7 +41,7 @@ LL | const NAN: f64 = f64::NAN;
    | -------------- constant defined here
 ...
 LL |         NAN..=1.0 => {},
-   |         ^^^
+   |         ^^^ evaluates to `NaN`, which is not allowed in patterns
    |
    = note: NaNs compare inequal to everything, even themselves, so this pattern would never match
    = help: try using the `is_nan` method instead
@@ -53,7 +53,7 @@ LL | const NAN: f64 = f64::NAN;
    | -------------- constant defined here
 ...
 LL |         -1.0..=NAN => {},
-   |                ^^^
+   |                ^^^ evaluates to `NaN`, which is not allowed in patterns
    |
    = note: NaNs compare inequal to everything, even themselves, so this pattern would never match
    = help: try using the `is_nan` method instead
@@ -65,7 +65,7 @@ LL | const NAN: f64 = f64::NAN;
    | -------------- constant defined here
 ...
 LL |         NAN.. => {},
-   |         ^^^
+   |         ^^^ evaluates to `NaN`, which is not allowed in patterns
    |
    = note: NaNs compare inequal to everything, even themselves, so this pattern would never match
    = help: try using the `is_nan` method instead
@@ -77,7 +77,7 @@ LL | const NAN: f64 = f64::NAN;
    | -------------- constant defined here
 ...
 LL |         ..NAN => {},
-   |           ^^^
+   |           ^^^ evaluates to `NaN`, which is not allowed in patterns
    |
    = note: NaNs compare inequal to everything, even themselves, so this pattern would never match
    = help: try using the `is_nan` method instead
diff --git a/tests/ui/union/union-const-pat.stderr b/tests/ui/union/union-const-pat.stderr
index baf32bf484950..59dc89c77a47c 100644
--- a/tests/ui/union/union-const-pat.stderr
+++ b/tests/ui/union/union-const-pat.stderr
@@ -5,7 +5,7 @@ LL | const C: U = U { a: 10 };
    | ---------- constant defined here
 ...
 LL |         C => {}
-   |         ^
+   |         ^ can't use a `union` here
 
 error: aborting due to 1 previous error
 

From a6040bc230bc7b26f413d7fbf60402e6e7940192 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 20 Nov 2024 04:06:39 +0000
Subject: [PATCH 13/21] Specify type kind of constant that can't be used in
 patterns

```
error: trait object `dyn Send` cannot be used in patterns
  --> $DIR/issue-70972-dyn-trait.rs:6:9
   |
LL | const F: &'static dyn Send = &7u32;
   | -------------------------- constant defined here
...
LL |         F => panic!(),
   |         ^ trait object can't be used in patterns
```
---
 compiler/rustc_mir_build/messages.ftl             |  3 ++-
 compiler/rustc_mir_build/src/errors.rs            |  2 ++
 .../src/thir/pattern/const_to_pat.rs              | 15 ++++++++++-----
 tests/ui/inline-const/pat-match-fndef.stderr      |  4 ++--
 tests/ui/match/issue-70972-dyn-trait.stderr       |  4 ++--
 tests/ui/pattern/issue-72565.stderr               |  4 ++--
 .../ui/pattern/non-structural-match-types.stderr  |  8 ++++----
 .../structural-match-no-leak.stderr               |  4 ++--
 .../type-alias-impl-trait/structural-match.stderr |  4 ++--
 9 files changed, 28 insertions(+), 20 deletions(-)

diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 28011833e5869..1e6b32bf60557 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -152,7 +152,8 @@ mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
 
 mir_build_interpreted_as_const = introduce a variable instead
 
-mir_build_invalid_pattern = `{$non_sm_ty}` cannot be used in patterns
+mir_build_invalid_pattern = {$prefix} `{$non_sm_ty}` cannot be used in patterns
+    .label = {$prefix} can't be used in patterns
 
 mir_build_irrefutable_let_patterns_if_let = irrefutable `if let` {$count ->
         [one] pattern
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 1c4de5c07a13e..2741830c62d0f 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -903,8 +903,10 @@ pub(crate) struct TypeNotPartialEq<'tcx> {
 #[diag(mir_build_invalid_pattern)]
 pub(crate) struct InvalidPattern<'tcx> {
     #[primary_span]
+    #[label]
     pub(crate) span: Span,
     pub(crate) non_sm_ty: Ty<'tcx>,
+    pub(crate) prefix: String,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index b625c655fac42..71cef18e3161b 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -171,10 +171,11 @@ impl<'tcx> ConstToPat<'tcx> {
                     ty::FnPtr(..) | ty::RawPtr(..) => {
                         self.tcx.dcx().create_err(PointerPattern { span: self.span })
                     }
-                    _ => self
-                        .tcx
-                        .dcx()
-                        .create_err(InvalidPattern { span: self.span, non_sm_ty: bad_ty }),
+                    _ => self.tcx.dcx().create_err(InvalidPattern {
+                        span: self.span,
+                        non_sm_ty: bad_ty,
+                        prefix: bad_ty.prefix_string(self.tcx).to_string(),
+                    }),
                 };
                 return self.mk_err(e, ty);
             }
@@ -373,7 +374,11 @@ impl<'tcx> ConstToPat<'tcx> {
                 )
             }
             _ => {
-                let err = InvalidPattern { span, non_sm_ty: ty };
+                let err = InvalidPattern {
+                    span,
+                    non_sm_ty: ty,
+                    prefix: ty.prefix_string(self.tcx).to_string(),
+                };
                 return Err(tcx.dcx().create_err(err));
             }
         };
diff --git a/tests/ui/inline-const/pat-match-fndef.stderr b/tests/ui/inline-const/pat-match-fndef.stderr
index b189ec51ade38..220437a0491af 100644
--- a/tests/ui/inline-const/pat-match-fndef.stderr
+++ b/tests/ui/inline-const/pat-match-fndef.stderr
@@ -1,8 +1,8 @@
-error: `fn() {uwu}` cannot be used in patterns
+error: fn item `fn() {uwu}` cannot be used in patterns
   --> $DIR/pat-match-fndef.rs:8:9
    |
 LL |         const { uwu } => {}
-   |         ^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^ fn item can't be used in patterns
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/match/issue-70972-dyn-trait.stderr b/tests/ui/match/issue-70972-dyn-trait.stderr
index 91f49c8a2ff10..cec9c8539f416 100644
--- a/tests/ui/match/issue-70972-dyn-trait.stderr
+++ b/tests/ui/match/issue-70972-dyn-trait.stderr
@@ -1,11 +1,11 @@
-error: `dyn Send` cannot be used in patterns
+error: trait object `dyn Send` cannot be used in patterns
   --> $DIR/issue-70972-dyn-trait.rs:6:9
    |
 LL | const F: &'static dyn Send = &7u32;
    | -------------------------- constant defined here
 ...
 LL |         F => panic!(),
-   |         ^
+   |         ^ trait object can't be used in patterns
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/pattern/issue-72565.stderr b/tests/ui/pattern/issue-72565.stderr
index abfd4512e9b8e..e2927ada0f70b 100644
--- a/tests/ui/pattern/issue-72565.stderr
+++ b/tests/ui/pattern/issue-72565.stderr
@@ -1,11 +1,11 @@
-error: `dyn PartialEq<u32>` cannot be used in patterns
+error: trait object `dyn PartialEq<u32>` cannot be used in patterns
   --> $DIR/issue-72565.rs:6:9
    |
 LL | const F: &'static dyn PartialEq<u32> = &7u32;
    | ------------------------------------ constant defined here
 ...
 LL |         F => panic!(),
-   |         ^
+   |         ^ trait object can't be used in patterns
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/pattern/non-structural-match-types.stderr b/tests/ui/pattern/non-structural-match-types.stderr
index 9075cf40ddae9..3588751bf6687 100644
--- a/tests/ui/pattern/non-structural-match-types.stderr
+++ b/tests/ui/pattern/non-structural-match-types.stderr
@@ -1,14 +1,14 @@
-error: `{closure@$DIR/non-structural-match-types.rs:9:17: 9:19}` cannot be used in patterns
+error: closure `{closure@$DIR/non-structural-match-types.rs:9:17: 9:19}` cannot be used in patterns
   --> $DIR/non-structural-match-types.rs:9:9
    |
 LL |         const { || {} } => {}
-   |         ^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^ closure can't be used in patterns
 
-error: `{async block@$DIR/non-structural-match-types.rs:12:17: 12:22}` cannot be used in patterns
+error: `async` block `{async block@$DIR/non-structural-match-types.rs:12:17: 12:22}` cannot be used in patterns
   --> $DIR/non-structural-match-types.rs:12:9
    |
 LL |         const { async {} } => {}
-   |         ^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^ `async` block can't be used in patterns
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/type-alias-impl-trait/structural-match-no-leak.stderr b/tests/ui/type-alias-impl-trait/structural-match-no-leak.stderr
index 743ad75628e25..28f5d6728a9de 100644
--- a/tests/ui/type-alias-impl-trait/structural-match-no-leak.stderr
+++ b/tests/ui/type-alias-impl-trait/structural-match-no-leak.stderr
@@ -1,11 +1,11 @@
-error: `Bar` cannot be used in patterns
+error: opaque type `Bar` cannot be used in patterns
   --> $DIR/structural-match-no-leak.rs:16:9
    |
 LL | const LEAK_FREE: bar::Bar = bar::leak_free();
    | ------------------------- constant defined here
 ...
 LL |         LEAK_FREE => (),
-   |         ^^^^^^^^^
+   |         ^^^^^^^^^ opaque type can't be used in patterns
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/type-alias-impl-trait/structural-match.stderr b/tests/ui/type-alias-impl-trait/structural-match.stderr
index 9c26aa9a9a645..b06b31a060fb9 100644
--- a/tests/ui/type-alias-impl-trait/structural-match.stderr
+++ b/tests/ui/type-alias-impl-trait/structural-match.stderr
@@ -1,11 +1,11 @@
-error: `foo::Foo` cannot be used in patterns
+error: opaque type `foo::Foo` cannot be used in patterns
   --> $DIR/structural-match.rs:18:9
    |
 LL | const VALUE: Foo = value();
    | ---------------- constant defined here
 ...
 LL |         VALUE => (),
-   |         ^^^^^
+   |         ^^^^^ opaque type can't be used in patterns
 
 error: aborting due to 1 previous error
 

From fb2f6a44c05c017139ef0266683fdfe3c66c4220 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 20 Nov 2024 04:15:37 +0000
Subject: [PATCH 14/21] Reword message for non-structural type constant in
 pattern

---
 compiler/rustc_mir_build/messages.ftl                          | 3 +--
 tests/ui/consts/const_in_pattern/issue-65466.rs                | 2 +-
 tests/ui/consts/const_in_pattern/issue-65466.stderr            | 2 +-
 tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs      | 2 +-
 tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr  | 2 +-
 tests/ui/match/issue-72896-non-partial-eq-const.rs             | 2 +-
 tests/ui/match/issue-72896-non-partial-eq-const.stderr         | 2 +-
 .../issue-61188-match-slice-forbidden-without-eq.rs            | 3 +--
 .../issue-61188-match-slice-forbidden-without-eq.stderr        | 2 +-
 9 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 1e6b32bf60557..df51388c7728b 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -273,8 +273,7 @@ mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type
     .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
     .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
-mir_build_non_partial_eq_match =
-    to use a constant of type `{$non_peq_ty}` in a pattern, the type must implement `PartialEq`
+mir_build_non_partial_eq_match = constant of non-structural type `{$non_peq_ty}` in a pattern
     .label = constant of non-structural type
 
 mir_build_pattern_not_covered = refutable pattern in {$origin}
diff --git a/tests/ui/consts/const_in_pattern/issue-65466.rs b/tests/ui/consts/const_in_pattern/issue-65466.rs
index 62efce648761a..82838657b02f5 100644
--- a/tests/ui/consts/const_in_pattern/issue-65466.rs
+++ b/tests/ui/consts/const_in_pattern/issue-65466.rs
@@ -11,7 +11,7 @@ const C: &[O<B>] = &[O::None];
 fn main() {
     let x = O::None;
     match &[x][..] {
-        C => (), //~ERROR: the type must implement `PartialEq`
+        C => (), //~ ERROR constant of non-structural type `&[O<B>]` in a pattern
         _ => (),
     }
 }
diff --git a/tests/ui/consts/const_in_pattern/issue-65466.stderr b/tests/ui/consts/const_in_pattern/issue-65466.stderr
index 90bac6262cc9d..c51d14d39f889 100644
--- a/tests/ui/consts/const_in_pattern/issue-65466.stderr
+++ b/tests/ui/consts/const_in_pattern/issue-65466.stderr
@@ -1,4 +1,4 @@
-error: to use a constant of type `&[O<B>]` in a pattern, the type must implement `PartialEq`
+error: constant of non-structural type `&[O<B>]` in a pattern
   --> $DIR/issue-65466.rs:14:9
    |
 LL | const C: &[O<B>] = &[O::None];
diff --git a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs
index 645e141891243..e555ecfeb8f1f 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs
+++ b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs
@@ -26,7 +26,7 @@ fn main() {
 
     match None {
         NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"),
-        //~^ ERROR must implement `PartialEq`
+        //~^ ERROR constant of non-structural type `Option<NoPartialEq>` in a pattern
         _ => panic!("whoops"),
     }
 }
diff --git a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
index d4952a8bfb8c6..2c9cda7d18533 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
+++ b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
@@ -1,4 +1,4 @@
-error: to use a constant of type `Option<NoPartialEq>` in a pattern, the type must implement `PartialEq`
+error: constant of non-structural type `Option<NoPartialEq>` in a pattern
   --> $DIR/reject_non_partial_eq.rs:28:9
    |
 LL | const NO_PARTIAL_EQ_NONE: Option<NoPartialEq> = None;
diff --git a/tests/ui/match/issue-72896-non-partial-eq-const.rs b/tests/ui/match/issue-72896-non-partial-eq-const.rs
index f15eae83896d1..e4fc1ac057d32 100644
--- a/tests/ui/match/issue-72896-non-partial-eq-const.rs
+++ b/tests/ui/match/issue-72896-non-partial-eq-const.rs
@@ -16,7 +16,7 @@ const CONST_SET: EnumSet<Enum8> = EnumSet { __enumset_underlying: 3 };
 
 fn main() {
     match CONST_SET {
-        CONST_SET => { /* ok */ } //~ERROR: must implement `PartialEq`
+        CONST_SET => { /* ok */ } //~ ERROR constant of non-structural type `EnumSet<Enum8>` in a pattern
         _ => panic!("match fell through?"),
     }
 }
diff --git a/tests/ui/match/issue-72896-non-partial-eq-const.stderr b/tests/ui/match/issue-72896-non-partial-eq-const.stderr
index d6ae9e56377d5..47323b3cd22c5 100644
--- a/tests/ui/match/issue-72896-non-partial-eq-const.stderr
+++ b/tests/ui/match/issue-72896-non-partial-eq-const.stderr
@@ -1,4 +1,4 @@
-error: to use a constant of type `EnumSet<Enum8>` in a pattern, the type must implement `PartialEq`
+error: constant of non-structural type `EnumSet<Enum8>` in a pattern
   --> $DIR/issue-72896-non-partial-eq-const.rs:19:9
    |
 LL | const CONST_SET: EnumSet<Enum8> = EnumSet { __enumset_underlying: 3 };
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs
index c01f8934c750e..95a3be517a9a5 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs
@@ -12,8 +12,7 @@ const A: &[B] = &[];
 
 pub fn main() {
     match &[][..] {
-        A => (),
-        //~^ ERROR must implement `PartialEq`
+        A => (), //~ ERROR constant of non-structural type `&[B]` in a pattern
         _ => (),
     }
 }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
index 51bcfc07c9e01..33244b2841fb7 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
@@ -1,4 +1,4 @@
-error: to use a constant of type `&[B]` in a pattern, the type must implement `PartialEq`
+error: constant of non-structural type `&[B]` in a pattern
   --> $DIR/issue-61188-match-slice-forbidden-without-eq.rs:15:9
    |
 LL | const A: &[B] = &[];

From 335d05aee555c19d375a46c34134312ac720aba0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 20 Nov 2024 04:30:35 +0000
Subject: [PATCH 15/21] Add additional context for non-sructural type constant
 used in pattern

- Point at type that should derive `PartialEq` to be structural.
- Point at manual `impl PartialEq`, explaining that it is not sufficient to be structural.

```
error: constant of non-structural type `MyType` in a pattern
  --> $DIR/const-partial_eq-fallback-ice.rs:14:12
   |
LL | struct MyType;
   | ------------- `MyType` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
...
LL | const CONSTANT: &&MyType = &&MyType;
   | ------------------------ constant defined here
...
LL |     if let CONSTANT = &&MyType {
   |            ^^^^^^^^ constant of non-structural type
   |
note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
  --> $DIR/const-partial_eq-fallback-ice.rs:5:1
   |
LL | impl PartialEq<usize> for MyType {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```
---
 compiler/rustc_mir_build/messages.ftl         |  10 +-
 compiler/rustc_mir_build/src/errors.rs        |   9 +-
 .../src/thir/pattern/const_to_pat.rs          |  23 ++-
 .../const_in_pattern/cross-crate-fail.rs      |   6 +-
 .../const_in_pattern/cross-crate-fail.stderr  |  22 ++-
 .../const_in_pattern/no-eq-branch-fail.rs     |   3 +-
 .../const_in_pattern/no-eq-branch-fail.stderr |   8 +-
 .../const_in_pattern/reject_non_structural.rs |  70 ++++----
 .../reject_non_structural.stderr              | 160 ++++++++++++------
 tests/ui/consts/issue-89088.rs                |   2 +-
 tests/ui/consts/issue-89088.stderr            |   8 +-
 tests/ui/consts/match_ice.rs                  |   3 +-
 tests/ui/consts/match_ice.stderr              |   8 +-
 tests/ui/pattern/issue-115599.rs              |   2 +-
 tests/ui/pattern/issue-115599.stderr          |   8 +-
 .../const-partial_eq-fallback-ice.rs          |   2 +-
 .../const-partial_eq-fallback-ice.stderr      |  14 +-
 ...cant-hide-behind-direct-struct-embedded.rs |   2 +-
 ...-hide-behind-direct-struct-embedded.stderr |  14 +-
 .../cant-hide-behind-direct-struct-param.rs   |   2 +-
 ...ant-hide-behind-direct-struct-param.stderr |  14 +-
 ...nt-hide-behind-doubly-indirect-embedded.rs |   2 +-
 ...ide-behind-doubly-indirect-embedded.stderr |  14 +-
 .../cant-hide-behind-doubly-indirect-param.rs |   2 +-
 ...t-hide-behind-doubly-indirect-param.stderr |  14 +-
 ...nt-hide-behind-indirect-struct-embedded.rs |   2 +-
 ...ide-behind-indirect-struct-embedded.stderr |  14 +-
 .../cant-hide-behind-indirect-struct-param.rs |   2 +-
 ...t-hide-behind-indirect-struct-param.stderr |  14 +-
 ...2307-match-ref-ref-forbidden-without-eq.rs |  12 +-
 ...-match-ref-ref-forbidden-without-eq.stderr |  32 ++--
 .../match-requires-both-partialeq-and-eq.rs   |   4 +-
 ...atch-requires-both-partialeq-and-eq.stderr |  16 +-
 33 files changed, 343 insertions(+), 175 deletions(-)

diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index df51388c7728b..6122307e5bb95 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -322,12 +322,12 @@ mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count ->
         *[other] them
     } into the body
 
-mir_build_type_not_structural =
-     to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq)]`
-
+mir_build_type_not_structural = constant of non-structural type `{$non_sm_ty}` in a pattern
+    .label = constant of non-structural type
+mir_build_type_not_structural_def = `{$non_sm_ty}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
 mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
-
-mir_build_type_not_structural_tip = the traits must be derived, manual `impl`s are not sufficient
+mir_build_type_not_structural_tip =
+    the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 mir_build_unconditional_recursion = function cannot return without recursing
     .label = cannot return without recursing
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 2741830c62d0f..da4c78ddc4ecf 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -882,12 +882,17 @@ pub(crate) struct UnionPattern {
 
 #[derive(Diagnostic)]
 #[diag(mir_build_type_not_structural)]
-#[note(mir_build_type_not_structural_tip)]
-#[note(mir_build_type_not_structural_more_info)]
 pub(crate) struct TypeNotStructural<'tcx> {
     #[primary_span]
+    #[label]
     pub(crate) span: Span,
+    #[label(mir_build_type_not_structural_def)]
+    pub(crate) ty_def_span: Span,
     pub(crate) non_sm_ty: Ty<'tcx>,
+    #[note(mir_build_type_not_structural_tip)]
+    pub(crate) manual_partialeq_impl_span: Option<Span>,
+    #[note(mir_build_type_not_structural_more_info)]
+    pub(crate) manual_partialeq_impl_note: bool,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 71cef18e3161b..36c84f68f7356 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -254,7 +254,22 @@ impl<'tcx> ConstToPat<'tcx> {
                 // Extremely important check for all ADTs! Make sure they opted-in to be used in
                 // patterns.
                 debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty);
-                let err = TypeNotStructural { span, non_sm_ty: ty };
+                let ty_def_span = tcx.def_span(adt_def.did());
+                let mut manual_partialeq_impl_span = None;
+                let partial_eq_trait_id =
+                    tcx.require_lang_item(hir::LangItem::PartialEq, Some(self.span));
+                tcx.for_each_relevant_impl(partial_eq_trait_id, ty, |def_id| {
+                    if def_id.is_local() {
+                        manual_partialeq_impl_span = Some(tcx.def_span(def_id));
+                    }
+                });
+                let err = TypeNotStructural {
+                    span,
+                    non_sm_ty: ty,
+                    ty_def_span,
+                    manual_partialeq_impl_span,
+                    manual_partialeq_impl_note: manual_partialeq_impl_span.is_none(),
+                };
                 return Err(tcx.dcx().create_err(err));
             }
             ty::Adt(adt_def, args) if adt_def.is_enum() => {
@@ -269,7 +284,7 @@ impl<'tcx> ConstToPat<'tcx> {
                             adt_def.variants()[variant_index]
                                 .fields
                                 .iter()
-                                .map(|field| field.ty(self.tcx, args)),
+                                .map(|field| field.ty(tcx, args)),
                         ),
                     ),
                 }
@@ -278,7 +293,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 assert!(!def.is_union()); // Valtree construction would never succeed for unions.
                 PatKind::Leaf {
                     subpatterns: self.field_pats(cv.unwrap_branch().iter().copied().zip(
-                        def.non_enum_variant().fields.iter().map(|field| field.ty(self.tcx, args)),
+                        def.non_enum_variant().fields.iter().map(|field| field.ty(tcx, args)),
                     )),
                 }
             }
@@ -377,7 +392,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 let err = InvalidPattern {
                     span,
                     non_sm_ty: ty,
-                    prefix: ty.prefix_string(self.tcx).to_string(),
+                    prefix: ty.prefix_string(tcx).to_string(),
                 };
                 return Err(tcx.dcx().create_err(err));
             }
diff --git a/tests/ui/consts/const_in_pattern/cross-crate-fail.rs b/tests/ui/consts/const_in_pattern/cross-crate-fail.rs
index 163a47f433369..f02e780f30e38 100644
--- a/tests/ui/consts/const_in_pattern/cross-crate-fail.rs
+++ b/tests/ui/consts/const_in_pattern/cross-crate-fail.rs
@@ -9,15 +9,13 @@ fn main() {
     let _ = Defaulted;
     match None {
         consts::SOME => panic!(),
-        //~^ must be annotated with `#[derive(PartialEq)]`
-
+        //~^ ERROR constant of non-structural type `CustomEq` in a pattern
         _ => {}
     }
 
     match None {
         <Defaulted as consts::AssocConst>::SOME  => panic!(),
-        //~^ must be annotated with `#[derive(PartialEq)]`
-
+        //~^ ERROR constant of non-structural type `CustomEq` in a pattern
         _ => {}
     }
 }
diff --git a/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr b/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr
index 81fc67e6aebb5..7cada8836450e 100644
--- a/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr
+++ b/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr
@@ -1,29 +1,33 @@
-error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq)]`
+error: constant of non-structural type `CustomEq` in a pattern
   --> $DIR/cross-crate-fail.rs:11:9
    |
 LL |         consts::SOME => panic!(),
-   |         ^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^ constant of non-structural type
    |
-  ::: $DIR/auxiliary/consts.rs:11:1
+  ::: $DIR/auxiliary/consts.rs:1:1
    |
+LL | pub struct CustomEq;
+   | ------------------- `CustomEq` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL | pub const SOME: Option<CustomEq> = Some(CustomEq);
    | -------------------------------- constant defined here
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
-error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/cross-crate-fail.rs:18:9
+error: constant of non-structural type `CustomEq` in a pattern
+  --> $DIR/cross-crate-fail.rs:17:9
    |
 LL |         <Defaulted as consts::AssocConst>::SOME  => panic!(),
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant of non-structural type
    |
-  ::: $DIR/auxiliary/consts.rs:15:5
+  ::: $DIR/auxiliary/consts.rs:1:1
    |
+LL | pub struct CustomEq;
+   | ------------------- `CustomEq` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL |     const SOME: Option<CustomEq> = Some(CustomEq);
    |     ---------------------------- constant defined here
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs
index cf013c1a79061..91ef5ac53295b 100644
--- a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs
+++ b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs
@@ -16,8 +16,7 @@ const BAR_BAZ: Foo = if 42 == 42 {
 
 fn main() {
     match Foo::Qux(NoEq) {
-        BAR_BAZ => panic!(),
-        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
+        BAR_BAZ => panic!(), //~ ERROR constant of non-structural type `Foo` in a pattern
         _ => {}
     }
 }
diff --git a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr
index 5e2fc6eca3c5d..154c94c6d3854 100644
--- a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr
+++ b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr
@@ -1,13 +1,15 @@
-error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq)]`
+error: constant of non-structural type `Foo` in a pattern
   --> $DIR/no-eq-branch-fail.rs:19:9
    |
+LL | enum Foo {
+   | -------- `Foo` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL | const BAR_BAZ: Foo = if 42 == 42 {
    | ------------------ constant defined here
 ...
 LL |         BAR_BAZ => panic!(),
-   |         ^^^^^^^
+   |         ^^^^^^^ constant of non-structural type
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.rs b/tests/ui/consts/const_in_pattern/reject_non_structural.rs
index 52cb974c1df1b..39e5f732a8985 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_structural.rs
+++ b/tests/ui/consts/const_in_pattern/reject_non_structural.rs
@@ -17,9 +17,29 @@ struct NoPartialEq;
 
 #[derive(Copy, Clone, Debug)]
 struct NoDerive;
+//~^ NOTE must be annotated with `#[derive(PartialEq)]`
+//~| NOTE must be annotated with `#[derive(PartialEq)]`
+//~| NOTE must be annotated with `#[derive(PartialEq)]`
+//~| NOTE must be annotated with `#[derive(PartialEq)]`
+//~| NOTE must be annotated with `#[derive(PartialEq)]`
+//~| NOTE must be annotated with `#[derive(PartialEq)]`
+//~| NOTE must be annotated with `#[derive(PartialEq)]`
+//~| NOTE must be annotated with `#[derive(PartialEq)]`
+//~| NOTE must be annotated with `#[derive(PartialEq)]`
+//~| NOTE must be annotated with `#[derive(PartialEq)]`
 
 // This impl makes `NoDerive` irreflexive.
 impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+//~^ NOTE StructuralPartialEq.html for details
+//~| NOTE StructuralPartialEq.html for details
+//~| NOTE StructuralPartialEq.html for details
+//~| NOTE StructuralPartialEq.html for details
+//~| NOTE StructuralPartialEq.html for details
+//~| NOTE StructuralPartialEq.html for details
+//~| NOTE StructuralPartialEq.html for details
+//~| NOTE StructuralPartialEq.html for details
+//~| NOTE StructuralPartialEq.html for details
+//~| NOTE StructuralPartialEq.html for details
 
 impl Eq for NoDerive { }
 
@@ -38,63 +58,53 @@ fn main() {
 
     const ENUM: Derive<NoDerive> = Derive::Some(NoDerive); //~ NOTE constant defined here
     match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
-    //~| NOTE the traits must be derived
-    //~| NOTE StructuralPartialEq.html for details
+    //~^ ERROR constant of non-structural type `NoDerive` in a pattern
+    //~| NOTE constant of non-structural type
 
     const FIELD: OND = TrivialEq(Some(NoDerive)).0; //~ NOTE constant defined here
     match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
-    //~| NOTE the traits must be derived
-    //~| NOTE StructuralPartialEq.html for details
+    //~^ ERROR constant of non-structural type `NoDerive` in a pattern
+    //~| NOTE constant of non-structural type
 
     const NO_DERIVE_SOME: OND = Some(NoDerive);
     const INDIRECT: OND = NO_DERIVE_SOME; //~ NOTE constant defined here
     match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
-    //~| NOTE the traits must be derived
-    //~| NOTE StructuralPartialEq.html for details
+    //~^ ERROR constant of non-structural type `NoDerive` in a pattern
+    //~| NOTE constant of non-structural type
 
     const TUPLE: (OND, OND) = (None, Some(NoDerive)); //~ NOTE constant defined here
     match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
-    //~| NOTE the traits must be derived
-    //~| NOTE StructuralPartialEq.html for details
+    //~^ ERROR constant of non-structural type `NoDerive` in a pattern
+    //~| NOTE constant of non-structural type
 
     const TYPE_ASCRIPTION: OND = type_ascribe!(Some(NoDerive), OND); //~ NOTE constant defined here
     match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
-    //~| NOTE the traits must be derived
-    //~| NOTE StructuralPartialEq.html for details
+    //~^ ERROR constant of non-structural type `NoDerive` in a pattern
+    //~| NOTE constant of non-structural type
 
     const ARRAY: [OND; 2] = [None, Some(NoDerive)]; //~ NOTE constant defined here
     match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
-    //~| NOTE the traits must be derived
-    //~| NOTE StructuralPartialEq.html for details
+    //~^ ERROR constant of non-structural type `NoDerive` in a pattern
+    //~| NOTE constant of non-structural type
 
     const REPEAT: [OND; 2] = [Some(NoDerive); 2]; //~ NOTE constant defined here
     match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
-    //~| NOTE the traits must be derived
-    //~| NOTE StructuralPartialEq.html for details
+    //~^ ERROR constant of non-structural type `NoDerive` in a pattern
+    //~| NOTE constant of non-structural type
 
     trait Trait: Sized { const ASSOC: Option<Self>; } //~ NOTE constant defined here
     impl Trait for NoDerive { const ASSOC: Option<NoDerive> = Some(NoDerive); }
     match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
-    //~| NOTE the traits must be derived
-    //~| NOTE StructuralPartialEq.html for details
+    //~^ ERROR constant of non-structural type `NoDerive` in a pattern
+    //~| NOTE constant of non-structural type
 
     const BLOCK: OND = { NoDerive; Some(NoDerive) }; //~ NOTE constant defined here
     match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
-    //~| NOTE the traits must be derived
-    //~| NOTE StructuralPartialEq.html for details
+    //~^ ERROR constant of non-structural type `NoDerive` in a pattern
+    //~| NOTE constant of non-structural type
 
     const ADDR_OF: &OND = &Some(NoDerive); //~ NOTE constant defined here
     match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
-    //~| NOTE the traits must be derived
-    //~| NOTE StructuralPartialEq.html for details
+    //~^ ERROR constant of non-structural type `NoDerive` in a pattern
+    //~| NOTE constant of non-structural type
 }
diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
index e8a69512e7eda..fa16d0b06a7fe 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
+++ b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
@@ -1,113 +1,173 @@
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/reject_non_structural.rs:40:36
+error: constant of non-structural type `NoDerive` in a pattern
+  --> $DIR/reject_non_structural.rs:60:36
    |
+LL | struct NoDerive;
+   | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL |     const ENUM: Derive<NoDerive> = Derive::Some(NoDerive);
    |     ---------------------------- constant defined here
 LL |     match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), };
-   |                                    ^^^^
+   |                                    ^^^^ constant of non-structural type
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/reject_non_structural.rs:32:1
+   |
+LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/reject_non_structural.rs:46:28
+error: constant of non-structural type `NoDerive` in a pattern
+  --> $DIR/reject_non_structural.rs:65:28
    |
+LL | struct NoDerive;
+   | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL |     const FIELD: OND = TrivialEq(Some(NoDerive)).0;
    |     ---------------- constant defined here
 LL |     match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), };
-   |                            ^^^^^
+   |                            ^^^^^ constant of non-structural type
+   |
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/reject_non_structural.rs:32:1
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/reject_non_structural.rs:53:27
+error: constant of non-structural type `NoDerive` in a pattern
+  --> $DIR/reject_non_structural.rs:71:27
    |
+LL | struct NoDerive;
+   | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL |     const INDIRECT: OND = NO_DERIVE_SOME;
    |     ------------------- constant defined here
 LL |     match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), };
-   |                           ^^^^^^^^
+   |                           ^^^^^^^^ constant of non-structural type
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/reject_non_structural.rs:32:1
+   |
+LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/reject_non_structural.rs:59:36
+error: constant of non-structural type `NoDerive` in a pattern
+  --> $DIR/reject_non_structural.rs:76:36
    |
+LL | struct NoDerive;
+   | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL |     const TUPLE: (OND, OND) = (None, Some(NoDerive));
    |     ----------------------- constant defined here
 LL |     match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), };
-   |                                    ^^^^^
+   |                                    ^^^^^ constant of non-structural type
+   |
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/reject_non_structural.rs:32:1
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/reject_non_structural.rs:65:28
+error: constant of non-structural type `NoDerive` in a pattern
+  --> $DIR/reject_non_structural.rs:81:28
    |
+LL | struct NoDerive;
+   | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL |     const TYPE_ASCRIPTION: OND = type_ascribe!(Some(NoDerive), OND);
    |     -------------------------- constant defined here
 LL |     match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), };
-   |                            ^^^^^^^^^^^^^^^
+   |                            ^^^^^^^^^^^^^^^ constant of non-structural type
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/reject_non_structural.rs:32:1
+   |
+LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/reject_non_structural.rs:71:36
+error: constant of non-structural type `NoDerive` in a pattern
+  --> $DIR/reject_non_structural.rs:86:36
    |
+LL | struct NoDerive;
+   | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL |     const ARRAY: [OND; 2] = [None, Some(NoDerive)];
    |     --------------------- constant defined here
 LL |     match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), };
-   |                                    ^^^^^
+   |                                    ^^^^^ constant of non-structural type
+   |
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/reject_non_structural.rs:32:1
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/reject_non_structural.rs:77:33
+error: constant of non-structural type `NoDerive` in a pattern
+  --> $DIR/reject_non_structural.rs:91:33
    |
+LL | struct NoDerive;
+   | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL |     const REPEAT: [OND; 2] = [Some(NoDerive); 2];
    |     ---------------------- constant defined here
 LL |     match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), };
-   |                                 ^^^^^^
+   |                                 ^^^^^^ constant of non-structural type
+   |
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/reject_non_structural.rs:32:1
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/reject_non_structural.rs:84:28
+error: constant of non-structural type `NoDerive` in a pattern
+  --> $DIR/reject_non_structural.rs:97:28
    |
+LL | struct NoDerive;
+   | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL |     trait Trait: Sized { const ASSOC: Option<Self>; }
    |     ------------------   ------------------------- constant defined here
 LL |     impl Trait for NoDerive { const ASSOC: Option<NoDerive> = Some(NoDerive); }
 LL |     match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), };
-   |                            ^^^^^^^^^^^^^^^
+   |                            ^^^^^^^^^^^^^^^ constant of non-structural type
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/reject_non_structural.rs:32:1
+   |
+LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/reject_non_structural.rs:90:28
+error: constant of non-structural type `NoDerive` in a pattern
+  --> $DIR/reject_non_structural.rs:102:28
    |
+LL | struct NoDerive;
+   | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL |     const BLOCK: OND = { NoDerive; Some(NoDerive) };
    |     ---------------- constant defined here
 LL |     match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), };
-   |                            ^^^^^
+   |                            ^^^^^ constant of non-structural type
+   |
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/reject_non_structural.rs:32:1
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/reject_non_structural.rs:96:29
+error: constant of non-structural type `NoDerive` in a pattern
+  --> $DIR/reject_non_structural.rs:107:29
    |
+LL | struct NoDerive;
+   | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL |     const ADDR_OF: &OND = &Some(NoDerive);
    |     ------------------- constant defined here
 LL |     match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), };
-   |                             ^^^^^^^
+   |                             ^^^^^^^ constant of non-structural type
+   |
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/reject_non_structural.rs:32:1
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 10 previous errors
 
diff --git a/tests/ui/consts/issue-89088.rs b/tests/ui/consts/issue-89088.rs
index 02a786e746513..f6dbf8f012502 100644
--- a/tests/ui/consts/issue-89088.rs
+++ b/tests/ui/consts/issue-89088.rs
@@ -13,7 +13,7 @@ fn main() {
     let var = A::Field(Cow::Borrowed("bar"));
 
     match &var {
-        FOO => todo!(), //~ERROR derive(PartialEq)
+        FOO => todo!(), //~ ERROR constant of non-structural type `Cow<'_, str>` in a pattern
         _ => todo!()
     }
 }
diff --git a/tests/ui/consts/issue-89088.stderr b/tests/ui/consts/issue-89088.stderr
index 740cc25647e52..56025e0d9b288 100644
--- a/tests/ui/consts/issue-89088.stderr
+++ b/tests/ui/consts/issue-89088.stderr
@@ -1,13 +1,15 @@
-error: to use a constant of type `Cow<'_, str>` in a pattern, `Cow<'_, str>` must be annotated with `#[derive(PartialEq)]`
+error: constant of non-structural type `Cow<'_, str>` in a pattern
   --> $DIR/issue-89088.rs:16:9
    |
 LL | const FOO: &A = &A::Field(Cow::Borrowed("foo"));
    | ------------- constant defined here
 ...
 LL |         FOO => todo!(),
-   |         ^^^
+   |         ^^^ constant of non-structural type
+  --> $SRC_DIR/alloc/src/borrow.rs:LL:COL
+   |
+   = note: `Cow<'_, str>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/consts/match_ice.rs b/tests/ui/consts/match_ice.rs
index ed1fd78809b12..477a2de09a46f 100644
--- a/tests/ui/consts/match_ice.rs
+++ b/tests/ui/consts/match_ice.rs
@@ -8,8 +8,7 @@ struct T;
 fn main() {
     const C: &S = &S;
     match C {
-        C => {}
-        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
+        C => {} //~ ERROR constant of non-structural type `S` in a pattern
     }
     const K: &T = &T;
     match K {
diff --git a/tests/ui/consts/match_ice.stderr b/tests/ui/consts/match_ice.stderr
index 0841ed050251a..95e96bbbd677d 100644
--- a/tests/ui/consts/match_ice.stderr
+++ b/tests/ui/consts/match_ice.stderr
@@ -1,13 +1,15 @@
-error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq)]`
+error: constant of non-structural type `S` in a pattern
   --> $DIR/match_ice.rs:11:9
    |
+LL | struct S;
+   | -------- `S` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL |     const C: &S = &S;
    |     ----------- constant defined here
 LL |     match C {
 LL |         C => {}
-   |         ^
+   |         ^ constant of non-structural type
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/pattern/issue-115599.rs b/tests/ui/pattern/issue-115599.rs
index 1521d728d9561..47fe6b87da942 100644
--- a/tests/ui/pattern/issue-115599.rs
+++ b/tests/ui/pattern/issue-115599.rs
@@ -3,5 +3,5 @@ const CONST_STRING: String = String::new();
 fn main() {
     let empty_str = String::from("");
     if let CONST_STRING = empty_str {}
-    //~^ ERROR to use a constant of type `Vec<u8>` in a pattern, `Vec<u8>` must be annotated with `#[derive(PartialEq)]`
+    //~^ ERROR constant of non-structural type `Vec<u8>` in a pattern
 }
diff --git a/tests/ui/pattern/issue-115599.stderr b/tests/ui/pattern/issue-115599.stderr
index 65e3b08ac4853..69d10728ccdd7 100644
--- a/tests/ui/pattern/issue-115599.stderr
+++ b/tests/ui/pattern/issue-115599.stderr
@@ -1,13 +1,15 @@
-error: to use a constant of type `Vec<u8>` in a pattern, `Vec<u8>` must be annotated with `#[derive(PartialEq)]`
+error: constant of non-structural type `Vec<u8>` in a pattern
   --> $DIR/issue-115599.rs:5:12
    |
 LL | const CONST_STRING: String = String::new();
    | -------------------------- constant defined here
 ...
 LL |     if let CONST_STRING = empty_str {}
-   |            ^^^^^^^^^^^^
+   |            ^^^^^^^^^^^^ constant of non-structural type
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+   |
+   = note: `Vec<u8>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.rs b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.rs
index f34093ef1498b..f09dcf8498f38 100644
--- a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.rs
+++ b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.rs
@@ -12,7 +12,7 @@ const CONSTANT: &&MyType = &&MyType;
 
 fn main() {
     if let CONSTANT = &&MyType {
-        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
+        //~^ ERROR constant of non-structural type `MyType` in a pattern
         println!("did match!");
     }
 }
diff --git a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
index bcbcd0bc280d8..f9da0430f2ef9 100644
--- a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
+++ b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
@@ -1,14 +1,20 @@
-error: to use a constant of type `MyType` in a pattern, `MyType` must be annotated with `#[derive(PartialEq)]`
+error: constant of non-structural type `MyType` in a pattern
   --> $DIR/const-partial_eq-fallback-ice.rs:14:12
    |
+LL | struct MyType;
+   | ------------- `MyType` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL | const CONSTANT: &&MyType = &&MyType;
    | ------------------------ constant defined here
 ...
 LL |     if let CONSTANT = &&MyType {
-   |            ^^^^^^^^
+   |            ^^^^^^^^ constant of non-structural type
+   |
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/const-partial_eq-fallback-ice.rs:5:1
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+LL | impl PartialEq<usize> for MyType {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs
index 65a85a5ed68f6..e27c804804971 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs
@@ -20,7 +20,7 @@ const WRAP_DIRECT_INLINE: WrapInline = WrapInline(NoDerive(0));
 fn main() {
     match WRAP_DIRECT_INLINE {
         WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); }
-        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
+        //~^ ERROR constant of non-structural type `NoDerive` in a pattern
         _ => { println!("WRAP_DIRECT_INLINE did not match itself"); }
     }
 }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr
index dffaafd88a088..8787d140e17ff 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr
@@ -1,14 +1,20 @@
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
+error: constant of non-structural type `NoDerive` in a pattern
   --> $DIR/cant-hide-behind-direct-struct-embedded.rs:22:9
    |
+LL | struct NoDerive(#[allow(dead_code)] i32);
+   | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL | const WRAP_DIRECT_INLINE: WrapInline = WrapInline(NoDerive(0));
    | ------------------------------------ constant defined here
 ...
 LL |         WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); }
-   |         ^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^ constant of non-structural type
+   |
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/cant-hide-behind-direct-struct-embedded.rs:11:1
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs
index f840b4040b653..713ff23573d43 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs
@@ -19,7 +19,7 @@ const WRAP_DIRECT_PARAM: WrapParam<NoDerive> = WrapParam(NoDerive(0));
 fn main() {
     match WRAP_DIRECT_PARAM {
         WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); }
-        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
+        //~^ ERROR constant of non-structural type `NoDerive` in a pattern
         _ => { println!("WRAP_DIRECT_PARAM did not match itself"); }
     }
 }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr
index 8da9fa71c536a..ec836db02ad8a 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr
@@ -1,14 +1,20 @@
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
+error: constant of non-structural type `NoDerive` in a pattern
   --> $DIR/cant-hide-behind-direct-struct-param.rs:21:9
    |
+LL | struct NoDerive(i32);
+   | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL | const WRAP_DIRECT_PARAM: WrapParam<NoDerive> = WrapParam(NoDerive(0));
    | -------------------------------------------- constant defined here
 ...
 LL |         WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); }
-   |         ^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^ constant of non-structural type
+   |
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/cant-hide-behind-direct-struct-param.rs:10:1
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs
index 898acefc83cc0..7766a4691923d 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs
@@ -20,7 +20,7 @@ const WRAP_DOUBLY_INDIRECT_INLINE: & &WrapInline = & &WrapInline(& & NoDerive(0)
 fn main() {
     match WRAP_DOUBLY_INDIRECT_INLINE {
         WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); }
-        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
+        //~^ ERROR constant of non-structural type `NoDerive` in a pattern
         _ => { println!("WRAP_DOUBLY_INDIRECT_INLINE correctly did not match itself"); }
     }
 }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr
index 3cd6a184bbe20..fdc16fe300c20 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr
@@ -1,14 +1,20 @@
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
+error: constant of non-structural type `NoDerive` in a pattern
   --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:22:9
    |
+LL | struct NoDerive(#[allow(dead_code)] i32);
+   | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL | const WRAP_DOUBLY_INDIRECT_INLINE: & &WrapInline = & &WrapInline(& & NoDerive(0));
    | ------------------------------------------------ constant defined here
 ...
 LL |         WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); }
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant of non-structural type
+   |
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:11:1
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs
index 7cbaada88a30a..ed84900b6e914 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs
@@ -20,7 +20,7 @@ const WRAP_DOUBLY_INDIRECT_PARAM: & &WrapParam<NoDerive> = & &WrapParam(& & NoDe
 fn main() {
     match WRAP_DOUBLY_INDIRECT_PARAM {
         WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); }
-        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
+        //~^ ERROR constant of non-structural type `NoDerive` in a pattern
         _ => { println!("WRAP_DOUBLY_INDIRECT_PARAM correctly did not match itself"); }
     }
 }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr
index 35693da99abf3..b46fc041f14b1 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr
@@ -1,14 +1,20 @@
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
+error: constant of non-structural type `NoDerive` in a pattern
   --> $DIR/cant-hide-behind-doubly-indirect-param.rs:22:9
    |
+LL | struct NoDerive(#[allow(dead_code)] i32);
+   | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL | const WRAP_DOUBLY_INDIRECT_PARAM: & &WrapParam<NoDerive> = & &WrapParam(& & NoDerive(0));
    | -------------------------------------------------------- constant defined here
 ...
 LL |         WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); }
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ constant of non-structural type
+   |
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/cant-hide-behind-doubly-indirect-param.rs:11:1
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs
index ac868efed6fd1..5743d7a24d3a3 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs
@@ -20,7 +20,7 @@ const WRAP_INDIRECT_INLINE: & &WrapInline = & &WrapInline(NoDerive(0));
 fn main() {
     match WRAP_INDIRECT_INLINE {
         WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); }
-        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
+        //~^ ERROR constant of non-structural type `NoDerive` in a pattern
         _ => { println!("WRAP_INDIRECT_INLINE did not match itself"); }
     }
 }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr
index 5312d61c44695..70f39aa01d822 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr
@@ -1,14 +1,20 @@
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
+error: constant of non-structural type `NoDerive` in a pattern
   --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:22:9
    |
+LL | struct NoDerive(#[allow(dead_code)] i32);
+   | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL | const WRAP_INDIRECT_INLINE: & &WrapInline = & &WrapInline(NoDerive(0));
    | ----------------------------------------- constant defined here
 ...
 LL |         WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); }
-   |         ^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^^ constant of non-structural type
+   |
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:11:1
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs
index cbfabec6819e9..9226f9c3ecdea 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs
@@ -20,7 +20,7 @@ const WRAP_INDIRECT_PARAM: & &WrapParam<NoDerive> = & &WrapParam(NoDerive(0));
 fn main() {
     match WRAP_INDIRECT_PARAM {
         WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); }
-        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
+        //~^ ERROR constant of non-structural type `NoDerive` in a pattern
         _ => { println!("WRAP_INDIRECT_PARAM correctly did not match itself"); }
     }
 }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr
index 2066c53e73a6b..fceb3acb025eb 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr
@@ -1,14 +1,20 @@
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
+error: constant of non-structural type `NoDerive` in a pattern
   --> $DIR/cant-hide-behind-indirect-struct-param.rs:22:9
    |
+LL | struct NoDerive(#[allow(dead_code)] i32);
+   | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL | const WRAP_INDIRECT_PARAM: & &WrapParam<NoDerive> = & &WrapParam(NoDerive(0));
    | ------------------------------------------------- constant defined here
 ...
 LL |         WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); }
-   |         ^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^^^^^^^^^^ constant of non-structural type
+   |
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/cant-hide-behind-indirect-struct-param.rs:11:1
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs
index 0fa2370c95bf4..843c5a3864907 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs
@@ -13,27 +13,35 @@
 
 #[derive(Debug)]
 struct B(i32);
+//~^ NOTE `B` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+//~| NOTE `B` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
 
 // Overriding `PartialEq` to use this strange notion of "equality" exposes
 // whether `match` is using structural-equality or method-dispatch
 // under the hood, which is the antithesis of rust-lang/rfcs#1445
 impl PartialEq for B {
+//~^ NOTE the `PartialEq` trait must be derived, manual `impl`s are not sufficient
+//~| NOTE the `PartialEq` trait must be derived, manual `impl`s are not sufficient
     fn eq(&self, other: &B) -> bool { std::cmp::min(self.0, other.0) == 0 }
 }
 
 fn main() {
     const RR_B0: & & B = & & B(0);
     const RR_B1: & & B = & & B(1);
+    //~^ NOTE constant defined here
+    //~| NOTE constant defined here
 
     match RR_B0 {
         RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); }
-        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
+        //~^ ERROR constant of non-structural type `B` in a pattern
+        //~| NOTE constant of non-structural type
         _ => { }
     }
 
     match RR_B1 {
         RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); }
-        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
+        //~^ ERROR constant of non-structural type `B` in a pattern
+        //~| NOTE constant of non-structural type
         _ => { }
     }
 }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr
index 5cfe6dabc8956..34fffd99c2c9f 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr
@@ -1,26 +1,38 @@
-error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:29:9
+error: constant of non-structural type `B` in a pattern
+  --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:35:9
    |
+LL | struct B(i32);
+   | -------- `B` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL |     const RR_B1: & & B = & & B(1);
    |     ------------------ constant defined here
 ...
 LL |         RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); }
-   |         ^^^^^
+   |         ^^^^^ constant of non-structural type
+   |
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:22:1
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+LL | impl PartialEq for B {
+   | ^^^^^^^^^^^^^^^^^^^^
 
-error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:35:9
+error: constant of non-structural type `B` in a pattern
+  --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:42:9
    |
+LL | struct B(i32);
+   | -------- `B` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL |     const RR_B1: & & B = & & B(1);
    |     ------------------ constant defined here
 ...
 LL |         RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); }
-   |         ^^^^^
+   |         ^^^^^ constant of non-structural type
+   |
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:22:1
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+LL | impl PartialEq for B {
+   | ^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs
index 9020eb291f5c5..74394698fbcd9 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs
@@ -1,3 +1,5 @@
+// Note: It is no longer true that both `Eq` and `PartialEq` must the derived, only the later.
+
 #[derive(Eq)]
 struct Foo {
     x: u32
@@ -15,7 +17,7 @@ fn main() {
     let y = Foo { x: 1 };
     match y {
         FOO => { }
-        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
+        //~^ ERROR constant of non-structural type `Foo` in a pattern
         _ => { }
     }
 }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr
index c471fe572548c..bbcab3b62d0e3 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr
@@ -1,14 +1,20 @@
-error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq)]`
-  --> $DIR/match-requires-both-partialeq-and-eq.rs:17:9
+error: constant of non-structural type `Foo` in a pattern
+  --> $DIR/match-requires-both-partialeq-and-eq.rs:19:9
    |
+LL | struct Foo {
+   | ---------- `Foo` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL | const FOO: Foo = Foo { x: 0 };
    | -------------- constant defined here
 ...
 LL |         FOO => { }
-   |         ^^^
+   |         ^^^ constant of non-structural type
+   |
+note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+  --> $DIR/match-requires-both-partialeq-and-eq.rs:8:1
    |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+LL | impl PartialEq for Foo {
+   | ^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 

From 27a1880593a057da01373c4cdafbbed3d34d650f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 20 Nov 2024 06:49:13 +0000
Subject: [PATCH 16/21] Add context to fall-through "const pattern of
 non-structural type" error

Unify wording with the regular non-structural type error.
---
 compiler/rustc_mir_build/messages.ftl                       | 6 +++---
 compiler/rustc_mir_build/src/errors.rs                      | 6 ++++--
 compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs   | 5 +++--
 tests/ui/consts/const_in_pattern/issue-65466.stderr         | 3 +++
 .../ui/consts/const_in_pattern/reject_non_partial_eq.stderr | 3 +++
 tests/ui/match/issue-72896-non-partial-eq-const.stderr      | 3 +++
 .../issue-61188-match-slice-forbidden-without-eq.stderr     | 3 +++
 7 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 6122307e5bb95..f35252dbcc55e 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -273,7 +273,7 @@ mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type
     .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
     .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
 
-mir_build_non_partial_eq_match = constant of non-structural type `{$non_peq_ty}` in a pattern
+mir_build_non_partial_eq_match = constant of non-structural type `{$ty}` in a pattern
     .label = constant of non-structural type
 
 mir_build_pattern_not_covered = refutable pattern in {$origin}
@@ -322,9 +322,9 @@ mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count ->
         *[other] them
     } into the body
 
-mir_build_type_not_structural = constant of non-structural type `{$non_sm_ty}` in a pattern
+mir_build_type_not_structural = constant of non-structural type `{$ty}` in a pattern
     .label = constant of non-structural type
-mir_build_type_not_structural_def = `{$non_sm_ty}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+mir_build_type_not_structural_def = `{$ty}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
 mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 mir_build_type_not_structural_tip =
     the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index da4c78ddc4ecf..49e18891fcabc 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -888,7 +888,7 @@ pub(crate) struct TypeNotStructural<'tcx> {
     pub(crate) span: Span,
     #[label(mir_build_type_not_structural_def)]
     pub(crate) ty_def_span: Span,
-    pub(crate) non_sm_ty: Ty<'tcx>,
+    pub(crate) ty: Ty<'tcx>,
     #[note(mir_build_type_not_structural_tip)]
     pub(crate) manual_partialeq_impl_span: Option<Span>,
     #[note(mir_build_type_not_structural_more_info)]
@@ -897,11 +897,13 @@ pub(crate) struct TypeNotStructural<'tcx> {
 
 #[derive(Diagnostic)]
 #[diag(mir_build_non_partial_eq_match)]
+#[note(mir_build_type_not_structural_def)]
+#[note(mir_build_type_not_structural_more_info)]
 pub(crate) struct TypeNotPartialEq<'tcx> {
     #[primary_span]
     #[label]
     pub(crate) span: Span,
-    pub(crate) non_peq_ty: Ty<'tcx>,
+    pub(crate) ty: Ty<'tcx>,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 36c84f68f7356..123a439c645a5 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -190,7 +190,8 @@ impl<'tcx> ConstToPat<'tcx> {
         if !inlined_const_as_pat.references_error() {
             // Always check for `PartialEq` if we had no other errors yet.
             if !self.type_has_partial_eq_impl(ty) {
-                let err = TypeNotPartialEq { span: self.span, non_peq_ty: ty };
+                let err = TypeNotPartialEq { span: self.span, ty };
+                // FIXME: visit every type in `ty` and if it doesn't derive `PartialEq`, mention it.
                 return self.mk_err(self.tcx.dcx().create_err(err), ty);
             }
         }
@@ -265,7 +266,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 });
                 let err = TypeNotStructural {
                     span,
-                    non_sm_ty: ty,
+                    ty,
                     ty_def_span,
                     manual_partialeq_impl_span,
                     manual_partialeq_impl_note: manual_partialeq_impl_span.is_none(),
diff --git a/tests/ui/consts/const_in_pattern/issue-65466.stderr b/tests/ui/consts/const_in_pattern/issue-65466.stderr
index c51d14d39f889..bd9748b5dda99 100644
--- a/tests/ui/consts/const_in_pattern/issue-65466.stderr
+++ b/tests/ui/consts/const_in_pattern/issue-65466.stderr
@@ -6,6 +6,9 @@ LL | const C: &[O<B>] = &[O::None];
 ...
 LL |         C => (),
    |         ^ constant of non-structural type
+   |
+   = note: `&[O<B>]` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
index 2c9cda7d18533..0ef5286e68937 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
+++ b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
@@ -6,6 +6,9 @@ LL | const NO_PARTIAL_EQ_NONE: Option<NoPartialEq> = None;
 ...
 LL |         NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"),
    |         ^^^^^^^^^^^^^^^^^^ constant of non-structural type
+   |
+   = note: `Option<NoPartialEq>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/match/issue-72896-non-partial-eq-const.stderr b/tests/ui/match/issue-72896-non-partial-eq-const.stderr
index 47323b3cd22c5..4287fbc188d59 100644
--- a/tests/ui/match/issue-72896-non-partial-eq-const.stderr
+++ b/tests/ui/match/issue-72896-non-partial-eq-const.stderr
@@ -6,6 +6,9 @@ LL | const CONST_SET: EnumSet<Enum8> = EnumSet { __enumset_underlying: 3 };
 ...
 LL |         CONST_SET => { /* ok */ }
    |         ^^^^^^^^^ constant of non-structural type
+   |
+   = note: `EnumSet<Enum8>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
index 33244b2841fb7..4f83ca02c2879 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
@@ -6,6 +6,9 @@ LL | const A: &[B] = &[];
 ...
 LL |         A => (),
    |         ^ constant of non-structural type
+   |
+   = note: `&[B]` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
 

From d136b3108def7af6d43229ba704ab21778f55125 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 20 Nov 2024 23:10:39 +0000
Subject: [PATCH 17/21] Add more context to fall-through "const pattern of
 non-structural type" error

Point at types that need to be marked with `#[derive(PartialEq)]`.

We use a visitor to look at a type that isn't structural, looking for all ADTs that don't derive `PartialEq`. These can either be manual `impl PartialEq`s or no `impl` at all, so we differentiate between those two cases to provide more context to the user. We also only point at types and impls from the local crate, otherwise show only a note.

```
error: constant of non-structural type `&[B]` in a pattern
  --> $DIR/issue-61188-match-slice-forbidden-without-eq.rs:15:9
   |
LL | struct B(i32);
   | -------- must be annotated with `#[derive(PartialEq)]` to be usable in patterns
LL |
LL | const A: &[B] = &[];
   | ------------- constant defined here
...
LL |         A => (),
   |         ^ constant of non-structural type
   |
   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
```
---
 compiler/rustc_mir_build/src/errors.rs        |   1 -
 .../src/thir/pattern/const_to_pat.rs          | 198 ++++++++++++++----
 .../const_in_pattern/issue-65466.stderr       |   4 +-
 .../reject_non_partial_eq.stderr              |   4 +-
 .../issue-72896-non-partial-eq-const.stderr   |   4 +-
 ...88-match-slice-forbidden-without-eq.stderr |   4 +-
 6 files changed, 169 insertions(+), 46 deletions(-)

diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 49e18891fcabc..3632da943e18b 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -897,7 +897,6 @@ pub(crate) struct TypeNotStructural<'tcx> {
 
 #[derive(Diagnostic)]
 #[diag(mir_build_non_partial_eq_match)]
-#[note(mir_build_type_not_structural_def)]
 #[note(mir_build_type_not_structural_more_info)]
 pub(crate) struct TypeNotPartialEq<'tcx> {
     #[primary_span]
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 123a439c645a5..feb6d2fcfe9c2 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,5 +1,6 @@
 use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_apfloat::Float;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Diag, PResult};
 use rustc_hir as hir;
 use rustc_index::Idx;
@@ -7,9 +8,10 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::Obligation;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::thir::{FieldPat, Pat, PatKind};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, ValTree};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypeVisitor, ValTree};
 use rustc_middle::{mir, span_bug};
-use rustc_span::Span;
+use rustc_span::def_id::DefId;
+use rustc_span::{Span, sym};
 use rustc_trait_selection::traits::ObligationCause;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use tracing::{debug, instrument, trace};
@@ -189,42 +191,16 @@ impl<'tcx> ConstToPat<'tcx> {
 
         if !inlined_const_as_pat.references_error() {
             // Always check for `PartialEq` if we had no other errors yet.
-            if !self.type_has_partial_eq_impl(ty) {
-                let err = TypeNotPartialEq { span: self.span, ty };
-                // FIXME: visit every type in `ty` and if it doesn't derive `PartialEq`, mention it.
-                return self.mk_err(self.tcx.dcx().create_err(err), ty);
+            if !type_has_partial_eq_impl(self.tcx, typing_env, ty).0 {
+                let mut err = self.tcx.dcx().create_err(TypeNotPartialEq { span: self.span, ty });
+                extend_type_not_partial_eq(self.tcx, typing_env, ty, &mut err);
+                return self.mk_err(err, ty);
             }
         }
 
         inlined_const_as_pat
     }
 
-    #[instrument(level = "trace", skip(self), ret)]
-    fn type_has_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool {
-        let (infcx, param_env) = self.tcx.infer_ctxt().build_with_typing_env(self.typing_env);
-        // double-check there even *is* a semantic `PartialEq` to dispatch to.
-        //
-        // (If there isn't, then we can safely issue a hard
-        // error, because that's never worked, due to compiler
-        // using `PartialEq::eq` in this scenario in the past.)
-        let partial_eq_trait_id =
-            self.tcx.require_lang_item(hir::LangItem::PartialEq, Some(self.span));
-        let partial_eq_obligation = Obligation::new(
-            self.tcx,
-            ObligationCause::dummy(),
-            param_env,
-            ty::TraitRef::new(self.tcx, partial_eq_trait_id, [ty, ty]),
-        );
-
-        // This *could* accept a type that isn't actually `PartialEq`, because region bounds get
-        // ignored. However that should be pretty much impossible since consts that do not depend on
-        // generics can only mention the `'static` lifetime, and how would one have a type that's
-        // `PartialEq` for some lifetime but *not* for `'static`? If this ever becomes a problem
-        // we'll need to leave some sort of trace of this requirement in the MIR so that borrowck
-        // can ensure that the type really implements `PartialEq`.
-        infcx.predicate_must_hold_modulo_regions(&partial_eq_obligation)
-    }
-
     fn field_pats(
         &self,
         vals: impl Iterator<Item = (ValTree<'tcx>, Ty<'tcx>)>,
@@ -255,21 +231,23 @@ impl<'tcx> ConstToPat<'tcx> {
                 // Extremely important check for all ADTs! Make sure they opted-in to be used in
                 // patterns.
                 debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty);
+                let (impls_partial_eq, derived, structural, impl_def_id) =
+                    type_has_partial_eq_impl(self.tcx, self.typing_env, ty);
+                let (manual_partialeq_impl_span, manual_partialeq_impl_note) =
+                    match (impls_partial_eq, derived, structural, impl_def_id) {
+                        (_, _, true, _) => (None, false),
+                        (_, false, _, Some(def_id)) if def_id.is_local() => {
+                            (Some(tcx.def_span(def_id)), false)
+                        }
+                        _ => (None, true),
+                    };
                 let ty_def_span = tcx.def_span(adt_def.did());
-                let mut manual_partialeq_impl_span = None;
-                let partial_eq_trait_id =
-                    tcx.require_lang_item(hir::LangItem::PartialEq, Some(self.span));
-                tcx.for_each_relevant_impl(partial_eq_trait_id, ty, |def_id| {
-                    if def_id.is_local() {
-                        manual_partialeq_impl_span = Some(tcx.def_span(def_id));
-                    }
-                });
                 let err = TypeNotStructural {
                     span,
                     ty,
                     ty_def_span,
                     manual_partialeq_impl_span,
-                    manual_partialeq_impl_note: manual_partialeq_impl_span.is_none(),
+                    manual_partialeq_impl_note,
                 };
                 return Err(tcx.dcx().create_err(err));
             }
@@ -402,3 +380,141 @@ impl<'tcx> ConstToPat<'tcx> {
         Ok(Box::new(Pat { span, ty, kind }))
     }
 }
+
+/// Given a type with type parameters, visit every ADT looking for types that need to
+/// `#[derive(PartialEq)]` to be a structural type.
+fn extend_type_not_partial_eq<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
+    ty: Ty<'tcx>,
+    err: &mut Diag<'_>,
+) {
+    /// Collect all types that need to be `StructuralPartialEq`.
+    struct UsedParamsNeedInstantiationVisitor<'tcx> {
+        tcx: TyCtxt<'tcx>,
+        typing_env: ty::TypingEnv<'tcx>,
+        /// The user has written `impl PartialEq for Ty` which means it's non-structual.
+        adts_with_manual_partialeq: FxHashSet<Span>,
+        /// The type has no `PartialEq` implementation, neither manual or derived.
+        adts_without_partialeq: FxHashSet<Span>,
+        /// The user has written `impl PartialEq for Ty` which means it's non-structual,
+        /// but we don't have a span to point at, so we'll just add them as a `note`.
+        manual: Vec<Ty<'tcx>>,
+        /// The type has no `PartialEq` implementation, neither manual or derived, but
+        /// we don't have a span to point at, so we'll just add them as a `note`.
+        without: Vec<Ty<'tcx>>,
+    }
+
+    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UsedParamsNeedInstantiationVisitor<'tcx> {
+        fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
+            if let ty::Adt(def, _args) = ty.kind() {
+                let ty_def_id = def.did();
+                let ty_def_span = self.tcx.def_span(ty_def_id);
+                let (impls_partial_eq, derived, structural, impl_def_id) =
+                    type_has_partial_eq_impl(self.tcx, self.typing_env, ty);
+                match (impls_partial_eq, derived, structural, impl_def_id) {
+                    (_, _, true, _) => {}
+                    (true, false, _, Some(def_id)) if def_id.is_local() => {
+                        self.adts_with_manual_partialeq.insert(self.tcx.def_span(def_id));
+                    }
+                    (true, false, _, _) if ty_def_id.is_local() => {
+                        self.adts_with_manual_partialeq.insert(ty_def_span);
+                    }
+                    (false, _, _, _) if ty_def_id.is_local() => {
+                        self.adts_without_partialeq.insert(ty_def_span);
+                    }
+                    (true, false, _, _) => {
+                        self.manual.push(ty);
+                    }
+                    (false, _, _, _) => {
+                        self.without.push(ty);
+                    }
+                    _ => {}
+                };
+            }
+            use rustc_middle::ty::TypeSuperVisitable;
+            ty.super_visit_with(self)
+        }
+    }
+    let mut v = UsedParamsNeedInstantiationVisitor {
+        tcx,
+        typing_env,
+        adts_with_manual_partialeq: FxHashSet::default(),
+        adts_without_partialeq: FxHashSet::default(),
+        manual: vec![],
+        without: vec![],
+    };
+    v.visit_ty(ty);
+    #[allow(rustc::potential_query_instability)] // Span labels will be sorted by the rendering
+    for span in v.adts_with_manual_partialeq {
+        err.span_note(span, "the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details");
+    }
+    #[allow(rustc::potential_query_instability)] // Span labels will be sorted by the rendering
+    for span in v.adts_without_partialeq {
+        err.span_label(
+            span,
+            "must be annotated with `#[derive(PartialEq)]` to be usable in patterns",
+        );
+    }
+    for ty in v.manual {
+        err.note(format!(
+            "`{ty}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details"
+        ));
+    }
+    for ty in v.without {
+        err.note(format!(
+            "`{ty}` must be annotated with `#[derive(PartialEq)]` to be usable in patterns"
+        ));
+    }
+}
+
+#[instrument(level = "trace", skip(tcx), ret)]
+fn type_has_partial_eq_impl<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
+    ty: Ty<'tcx>,
+) -> (
+    /* has impl */ bool,
+    /* is derived */ bool,
+    /* structural partial eq */ bool,
+    /* non-blanket impl */ Option<DefId>,
+) {
+    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
+    // double-check there even *is* a semantic `PartialEq` to dispatch to.
+    //
+    // (If there isn't, then we can safely issue a hard
+    // error, because that's never worked, due to compiler
+    // using `PartialEq::eq` in this scenario in the past.)
+    let partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::PartialEq, None);
+    let structural_partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::StructuralPeq, None);
+
+    let partial_eq_obligation = Obligation::new(
+        tcx,
+        ObligationCause::dummy(),
+        param_env,
+        ty::TraitRef::new(tcx, partial_eq_trait_id, [ty, ty]),
+    );
+
+    let mut automatically_derived = false;
+    let mut structural_peq = false;
+    let mut impl_def_id = None;
+    for def_id in tcx.non_blanket_impls_for_ty(partial_eq_trait_id, ty) {
+        automatically_derived = tcx.has_attr(def_id, sym::automatically_derived);
+        impl_def_id = Some(def_id);
+    }
+    for _ in tcx.non_blanket_impls_for_ty(structural_partial_eq_trait_id, ty) {
+        structural_peq = true;
+    }
+    // This *could* accept a type that isn't actually `PartialEq`, because region bounds get
+    // ignored. However that should be pretty much impossible since consts that do not depend on
+    // generics can only mention the `'static` lifetime, and how would one have a type that's
+    // `PartialEq` for some lifetime but *not* for `'static`? If this ever becomes a problem
+    // we'll need to leave some sort of trace of this requirement in the MIR so that borrowck
+    // can ensure that the type really implements `PartialEq`.
+    (
+        infcx.predicate_must_hold_modulo_regions(&partial_eq_obligation),
+        automatically_derived,
+        structural_peq,
+        impl_def_id,
+    )
+}
diff --git a/tests/ui/consts/const_in_pattern/issue-65466.stderr b/tests/ui/consts/const_in_pattern/issue-65466.stderr
index bd9748b5dda99..511a38bbc00d8 100644
--- a/tests/ui/consts/const_in_pattern/issue-65466.stderr
+++ b/tests/ui/consts/const_in_pattern/issue-65466.stderr
@@ -1,13 +1,15 @@
 error: constant of non-structural type `&[O<B>]` in a pattern
   --> $DIR/issue-65466.rs:14:9
    |
+LL | struct B;
+   | -------- must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+LL |
 LL | const C: &[O<B>] = &[O::None];
    | ---------------- constant defined here
 ...
 LL |         C => (),
    |         ^ constant of non-structural type
    |
-   = note: `&[O<B>]` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
index 0ef5286e68937..43894f0088621 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
+++ b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
@@ -1,13 +1,15 @@
 error: constant of non-structural type `Option<NoPartialEq>` in a pattern
   --> $DIR/reject_non_partial_eq.rs:28:9
    |
+LL | struct NoPartialEq(u32);
+   | ------------------ must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL | const NO_PARTIAL_EQ_NONE: Option<NoPartialEq> = None;
    | --------------------------------------------- constant defined here
 ...
 LL |         NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"),
    |         ^^^^^^^^^^^^^^^^^^ constant of non-structural type
    |
-   = note: `Option<NoPartialEq>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/match/issue-72896-non-partial-eq-const.stderr b/tests/ui/match/issue-72896-non-partial-eq-const.stderr
index 4287fbc188d59..1f82d3e822adb 100644
--- a/tests/ui/match/issue-72896-non-partial-eq-const.stderr
+++ b/tests/ui/match/issue-72896-non-partial-eq-const.stderr
@@ -1,13 +1,15 @@
 error: constant of non-structural type `EnumSet<Enum8>` in a pattern
   --> $DIR/issue-72896-non-partial-eq-const.rs:19:9
    |
+LL | enum Enum8 { }
+   | ---------- must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+...
 LL | const CONST_SET: EnumSet<Enum8> = EnumSet { __enumset_underlying: 3 };
    | ------------------------------- constant defined here
 ...
 LL |         CONST_SET => { /* ok */ }
    |         ^^^^^^^^^ constant of non-structural type
    |
-   = note: `EnumSet<Enum8>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
index 4f83ca02c2879..7d3b37686b865 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
@@ -1,13 +1,15 @@
 error: constant of non-structural type `&[B]` in a pattern
   --> $DIR/issue-61188-match-slice-forbidden-without-eq.rs:15:9
    |
+LL | struct B(i32);
+   | -------- must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+LL |
 LL | const A: &[B] = &[];
    | ------------- constant defined here
 ...
 LL |         A => (),
    |         ^ constant of non-structural type
    |
-   = note: `&[B]` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error

From da58406c73524054e9915aee4aa44d415868be6b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 20 Nov 2024 23:10:52 +0000
Subject: [PATCH 18/21] fix test

---
 tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr
index 8175fe6016ab8..18935626af1ca 100644
--- a/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr
+++ b/tests/ui/consts/const-eval/ref_to_int_match.32bit.stderr
@@ -7,12 +7,6 @@ LL | const BAR: Int = unsafe { Foo { r: &42 }.f };
    = help: this code performed an operation that depends on the underlying bytes representing a pointer
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
-error: could not evaluate constant pattern
-  --> $DIR/ref_to_int_match.rs:7:14
-   |
-LL |         10..=BAR => {},
-   |              ^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0080`.

From 81291ec7eaf824d748ef8d3201d13df444ada4ef Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Wed, 4 Dec 2024 20:29:02 +0000
Subject: [PATCH 19/21] No need to create placeholders for GAT args in
 confirm_object_candidate

---
 .../src/traits/select/confirmation.rs         | 54 +------------------
 1 file changed, 2 insertions(+), 52 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 19b4125e75cdf..2fbe2e1e323be 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -16,9 +16,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk};
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
-use rustc_middle::ty::{
-    self, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, Ty, TyCtxt, Upcast,
-};
+use rustc_middle::ty::{self, GenericArgsRef, ToPolyTraitRef, Ty, TyCtxt, Upcast};
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 use tracing::{debug, instrument};
@@ -638,60 +636,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // higher-ranked things.
             // Prevent, e.g., `dyn Iterator<Item = str>`.
             for bound in self.tcx().item_bounds(assoc_type).transpose_iter() {
-                let arg_bound = if defs.is_empty() {
-                    bound.instantiate(tcx, trait_predicate.trait_ref.args)
-                } else {
-                    let mut args = smallvec::SmallVec::with_capacity(defs.count());
-                    args.extend(trait_predicate.trait_ref.args.iter());
-                    let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
-                        smallvec::SmallVec::with_capacity(
-                            bound.skip_binder().kind().bound_vars().len() + defs.count(),
-                        );
-                    bound_vars.extend(bound.skip_binder().kind().bound_vars().into_iter());
-                    GenericArgs::fill_single(&mut args, defs, &mut |param, _| match param.kind {
-                        GenericParamDefKind::Type { .. } => {
-                            let kind = ty::BoundTyKind::Param(param.def_id, param.name);
-                            let bound_var = ty::BoundVariableKind::Ty(kind);
-                            bound_vars.push(bound_var);
-                            Ty::new_bound(tcx, ty::INNERMOST, ty::BoundTy {
-                                var: ty::BoundVar::from_usize(bound_vars.len() - 1),
-                                kind,
-                            })
-                            .into()
-                        }
-                        GenericParamDefKind::Lifetime => {
-                            let kind = ty::BoundRegionKind::Named(param.def_id, param.name);
-                            let bound_var = ty::BoundVariableKind::Region(kind);
-                            bound_vars.push(bound_var);
-                            ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion {
-                                var: ty::BoundVar::from_usize(bound_vars.len() - 1),
-                                kind,
-                            })
-                            .into()
-                        }
-                        GenericParamDefKind::Const { .. } => {
-                            let bound_var = ty::BoundVariableKind::Const;
-                            bound_vars.push(bound_var);
-                            ty::Const::new_bound(
-                                tcx,
-                                ty::INNERMOST,
-                                ty::BoundVar::from_usize(bound_vars.len() - 1),
-                            )
-                            .into()
-                        }
-                    });
-                    let bound_vars = tcx.mk_bound_variable_kinds(&bound_vars);
-                    let assoc_ty_args = tcx.mk_args(&args);
-                    let bound =
-                        bound.map_bound(|b| b.kind().skip_binder()).instantiate(tcx, assoc_ty_args);
-                    ty::Binder::bind_with_vars(bound, bound_vars).upcast(tcx)
-                };
                 let normalized_bound = normalize_with_depth_to(
                     self,
                     obligation.param_env,
                     obligation.cause.clone(),
                     obligation.recursion_depth + 1,
-                    arg_bound,
+                    bound.instantiate(tcx, trait_predicate.trait_ref.args),
                     &mut nested,
                 );
                 nested.push(obligation.with(tcx, normalized_bound));

From 4e6a401b224342287469a1a294bba7ad10e8641c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 4 Dec 2024 20:49:05 +0000
Subject: [PATCH 20/21] review comments: reword messages and simplify logic

---
 compiler/rustc_mir_build/messages.ftl         |  2 +-
 .../src/thir/pattern/const_to_pat.rs          | 64 +++++++------------
 ...associated-const-type-parameter-pattern.rs |  8 +--
 ...ciated-const-type-parameter-pattern.stderr | 16 ++---
 tests/ui/consts/issue-73976-polymorphic.rs    |  4 +-
 .../ui/consts/issue-73976-polymorphic.stderr  |  8 +--
 tests/ui/consts/issue-79137-toogeneric.rs     |  2 +-
 tests/ui/consts/issue-79137-toogeneric.stderr |  4 +-
 .../inline-const/const-match-pat-generic.rs   |  4 +-
 .../const-match-pat-generic.stderr            |  4 +-
 10 files changed, 48 insertions(+), 68 deletions(-)

diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index f35252dbcc55e..f647486f62ade 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -90,7 +90,7 @@ mir_build_const_param_in_pattern = constant parameters cannot be referenced in p
     .label = can't be used in patterns
 mir_build_const_param_in_pattern_def = constant defined here
 
-mir_build_const_pattern_depends_on_generic_parameter = constant pattern depends on a generic parameter, which is not allowed
+mir_build_const_pattern_depends_on_generic_parameter = constant pattern cannot depend on generic parameters
     .label = `const` depends on a generic parameter
 
 mir_build_could_not_eval_const_pattern = could not evaluate constant pattern
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index feb6d2fcfe9c2..aed00aecefc99 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,7 +1,7 @@
 use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_apfloat::Float;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Diag, PResult};
+use rustc_errors::Diag;
 use rustc_hir as hir;
 use rustc_index::Idx;
 use rustc_infer::infer::TyCtxtInferExt;
@@ -42,10 +42,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
         match c.kind() {
             ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty),
-            ty::ConstKind::Value(_, val) => match convert.valtree_to_pat(val, ty) {
-                Ok(pat) => pat,
-                Err(err) => convert.mk_err(err, ty),
-            },
+            ty::ConstKind::Value(_, val) => convert.valtree_to_pat(val, ty),
             _ => span_bug!(span, "Invalid `ConstKind` for `const_to_pat`: {:?}", c),
         }
     }
@@ -151,7 +148,7 @@ impl<'tcx> ConstToPat<'tcx> {
                         let generics = self.tcx.generics_of(def_id);
                         let param = generics.type_param(*param_ty, self.tcx);
                         let span = self.tcx.def_span(param.def_id);
-                        e.span_label(span, "constant depends on this generic param");
+                        e.span_label(span, "constant depends on this generic parameter");
                         if let Some(ident) = self.tcx.def_ident_span(def_id)
                             && self.tcx.sess.source_map().is_multiline(ident.between(span))
                         {
@@ -184,10 +181,7 @@ impl<'tcx> ConstToPat<'tcx> {
         };
 
         // Convert the valtree to a const.
-        let inlined_const_as_pat = match self.valtree_to_pat(valtree, ty) {
-            Ok(pat) => pat,
-            Err(err) => self.mk_err(err, ty),
-        };
+        let inlined_const_as_pat = self.valtree_to_pat(valtree, ty);
 
         if !inlined_const_as_pat.references_error() {
             // Always check for `PartialEq` if we had no other errors yet.
@@ -210,20 +204,14 @@ impl<'tcx> ConstToPat<'tcx> {
                 let field = FieldIdx::new(idx);
                 // Patterns can only use monomorphic types.
                 let ty = self.tcx.normalize_erasing_regions(self.typing_env, ty);
-                FieldPat {
-                    field,
-                    pattern: match self.valtree_to_pat(val, ty) {
-                        Ok(pat) => pat,
-                        Err(err) => self.mk_err(err, ty),
-                    },
-                }
+                FieldPat { field, pattern: self.valtree_to_pat(val, ty) }
             })
             .collect()
     }
 
     // Recursive helper for `to_pat`; invoke that (instead of calling this directly).
     #[instrument(skip(self), level = "debug")]
-    fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> PResult<'_, Box<Pat<'tcx>>> {
+    fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
         let span = self.span;
         let tcx = self.tcx;
         let kind = match ty.kind() {
@@ -231,12 +219,12 @@ impl<'tcx> ConstToPat<'tcx> {
                 // Extremely important check for all ADTs! Make sure they opted-in to be used in
                 // patterns.
                 debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty);
-                let (impls_partial_eq, derived, structural, impl_def_id) =
+                let (_impls_partial_eq, derived, structural, impl_def_id) =
                     type_has_partial_eq_impl(self.tcx, self.typing_env, ty);
                 let (manual_partialeq_impl_span, manual_partialeq_impl_note) =
-                    match (impls_partial_eq, derived, structural, impl_def_id) {
-                        (_, _, true, _) => (None, false),
-                        (_, false, _, Some(def_id)) if def_id.is_local() => {
+                    match (structural, impl_def_id) {
+                        (true, _) => (None, false),
+                        (_, Some(def_id)) if def_id.is_local() && !derived => {
                             (Some(tcx.def_span(def_id)), false)
                         }
                         _ => (None, true),
@@ -249,7 +237,7 @@ impl<'tcx> ConstToPat<'tcx> {
                     manual_partialeq_impl_span,
                     manual_partialeq_impl_note,
                 };
-                return Err(tcx.dcx().create_err(err));
+                return self.mk_err(tcx.dcx().create_err(err), ty);
             }
             ty::Adt(adt_def, args) if adt_def.is_enum() => {
                 let (&variant_index, fields) = cv.unwrap_branch().split_first().unwrap();
@@ -283,10 +271,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 prefix: cv
                     .unwrap_branch()
                     .iter()
-                    .map(|val| match self.valtree_to_pat(*val, *elem_ty) {
-                        Ok(pat) => pat,
-                        Err(err) => self.mk_err(err, ty),
-                    })
+                    .map(|val| self.valtree_to_pat(*val, *elem_ty))
                     .collect(),
                 slice: None,
                 suffix: Box::new([]),
@@ -295,10 +280,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 prefix: cv
                     .unwrap_branch()
                     .iter()
-                    .map(|val| match self.valtree_to_pat(*val, *elem_ty) {
-                        Ok(pat) => pat,
-                        Err(err) => self.mk_err(err, ty),
-                    })
+                    .map(|val| self.valtree_to_pat(*val, *elem_ty))
                     .collect(),
                 slice: None,
                 suffix: Box::new([]),
@@ -314,9 +296,10 @@ impl<'tcx> ConstToPat<'tcx> {
                 // deref pattern.
                 _ => {
                     if !pointee_ty.is_sized(tcx, self.typing_env) && !pointee_ty.is_slice() {
-                        return Err(tcx
-                            .dcx()
-                            .create_err(UnsizedPattern { span, non_sm_ty: *pointee_ty }));
+                        return self.mk_err(
+                            tcx.dcx().create_err(UnsizedPattern { span, non_sm_ty: *pointee_ty }),
+                            ty,
+                        );
                     } else {
                         // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
                         // matching against references, you can only use byte string literals.
@@ -331,10 +314,7 @@ impl<'tcx> ConstToPat<'tcx> {
                             _ => *pointee_ty,
                         };
                         // References have the same valtree representation as their pointee.
-                        let subpattern = match self.valtree_to_pat(cv, pointee_ty) {
-                            Ok(pat) => pat,
-                            Err(err) => self.mk_err(err, ty),
-                        };
+                        let subpattern = self.valtree_to_pat(cv, pointee_ty);
                         PatKind::Deref { subpattern }
                     }
                 }
@@ -350,7 +330,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 if is_nan {
                     // NaNs are not ever equal to anything so they make no sense as patterns.
                     // Also see <https://github.com/rust-lang/rfcs/pull/3535>.
-                    return Err(tcx.dcx().create_err(NaNPattern { span }));
+                    return self.mk_err(tcx.dcx().create_err(NaNPattern { span }), ty);
                 } else {
                     PatKind::Constant {
                         value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)),
@@ -373,16 +353,16 @@ impl<'tcx> ConstToPat<'tcx> {
                     non_sm_ty: ty,
                     prefix: ty.prefix_string(tcx).to_string(),
                 };
-                return Err(tcx.dcx().create_err(err));
+                return self.mk_err(tcx.dcx().create_err(err), ty);
             }
         };
 
-        Ok(Box::new(Pat { span, ty, kind }))
+        Box::new(Pat { span, ty, kind })
     }
 }
 
 /// Given a type with type parameters, visit every ADT looking for types that need to
-/// `#[derive(PartialEq)]` to be a structural type.
+/// `#[derive(PartialEq)]` for it to be a structural type.
 fn extend_type_not_partial_eq<'tcx>(
     tcx: TyCtxt<'tcx>,
     typing_env: ty::TypingEnv<'tcx>,
diff --git a/tests/ui/associated-consts/associated-const-type-parameter-pattern.rs b/tests/ui/associated-consts/associated-const-type-parameter-pattern.rs
index b5798adc71c86..e6c80a7e54e85 100644
--- a/tests/ui/associated-consts/associated-const-type-parameter-pattern.rs
+++ b/tests/ui/associated-consts/associated-const-type-parameter-pattern.rs
@@ -18,17 +18,17 @@ impl Foo for Def {
 pub fn test<A: Foo, B: Foo>(arg: EFoo) {
     match arg {
         A::X => println!("A::X"),
-        //~^ error: constant pattern depends on a generic parameter
+        //~^ ERROR constant pattern cannot depend on generic parameters
         B::X => println!("B::X"),
-        //~^ error: constant pattern depends on a generic parameter
+        //~^ ERROR constant pattern cannot depend on generic parameters
         _ => (),
     }
 }
 
 pub fn test_let_pat<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
-    //~^ ERROR constant pattern depends on a generic parameter
+    //~^ ERROR constant pattern cannot depend on generic parameters
     let A::X = arg;
-    //~^ ERROR constant pattern depends on a generic parameter
+    //~^ ERROR constant pattern cannot depend on generic parameters
 }
 
 fn main() {
diff --git a/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr b/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr
index 455831e8401cb..a8256f775a68c 100644
--- a/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr
+++ b/tests/ui/associated-consts/associated-const-type-parameter-pattern.stderr
@@ -1,4 +1,4 @@
-error[E0158]: constant pattern depends on a generic parameter, which is not allowed
+error[E0158]: constant pattern cannot depend on generic parameters
   --> $DIR/associated-const-type-parameter-pattern.rs:20:9
    |
 LL | pub trait Foo {
@@ -7,12 +7,12 @@ LL |     const X: EFoo;
    |     ------------- constant defined here
 ...
 LL | pub fn test<A: Foo, B: Foo>(arg: EFoo) {
-   |             - constant depends on this generic param
+   |             - constant depends on this generic parameter
 LL |     match arg {
 LL |         A::X => println!("A::X"),
    |         ^^^^ `const` depends on a generic parameter
 
-error[E0158]: constant pattern depends on a generic parameter, which is not allowed
+error[E0158]: constant pattern cannot depend on generic parameters
   --> $DIR/associated-const-type-parameter-pattern.rs:22:9
    |
 LL | pub trait Foo {
@@ -21,12 +21,12 @@ LL |     const X: EFoo;
    |     ------------- constant defined here
 ...
 LL | pub fn test<A: Foo, B: Foo>(arg: EFoo) {
-   |                     - constant depends on this generic param
+   |                     - constant depends on this generic parameter
 ...
 LL |         B::X => println!("B::X"),
    |         ^^^^ `const` depends on a generic parameter
 
-error[E0158]: constant pattern depends on a generic parameter, which is not allowed
+error[E0158]: constant pattern cannot depend on generic parameters
   --> $DIR/associated-const-type-parameter-pattern.rs:30:9
    |
 LL | pub trait Foo {
@@ -35,12 +35,12 @@ LL |     const X: EFoo;
    |     ------------- constant defined here
 ...
 LL | pub fn test_let_pat<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
-   |                     - constant depends on this generic param
+   |                     - constant depends on this generic parameter
 LL |
 LL |     let A::X = arg;
    |         ^^^^ `const` depends on a generic parameter
 
-error[E0158]: constant pattern depends on a generic parameter, which is not allowed
+error[E0158]: constant pattern cannot depend on generic parameters
   --> $DIR/associated-const-type-parameter-pattern.rs:28:48
    |
 LL | pub trait Foo {
@@ -51,7 +51,7 @@ LL |     const X: EFoo;
 LL | pub fn test_let_pat<A: Foo, B: Foo>(arg: EFoo, A::X: EFoo) {
    |                     -                          ^^^^ `const` depends on a generic parameter
    |                     |
-   |                     constant depends on this generic param
+   |                     constant depends on this generic parameter
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/consts/issue-73976-polymorphic.rs b/tests/ui/consts/issue-73976-polymorphic.rs
index 2c576d1f9ef08..98b4005792dbc 100644
--- a/tests/ui/consts/issue-73976-polymorphic.rs
+++ b/tests/ui/consts/issue-73976-polymorphic.rs
@@ -18,7 +18,7 @@ impl<T: 'static> GetTypeId<T> {
 
 const fn check_type_id<T: 'static>() -> bool {
     matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
-    //~^ ERROR constant pattern depends on a generic parameter
+    //~^ ERROR constant pattern cannot depend on generic parameters
 }
 
 pub struct GetTypeNameLen<T>(T);
@@ -29,7 +29,7 @@ impl<T: 'static> GetTypeNameLen<T> {
 
 const fn check_type_name_len<T: 'static>() -> bool {
     matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
-    //~^ ERROR constant pattern depends on a generic parameter
+    //~^ ERROR constant pattern cannot depend on generic parameters
 }
 
 fn main() {
diff --git a/tests/ui/consts/issue-73976-polymorphic.stderr b/tests/ui/consts/issue-73976-polymorphic.stderr
index 2f50e6ac2fd42..ec9512a261632 100644
--- a/tests/ui/consts/issue-73976-polymorphic.stderr
+++ b/tests/ui/consts/issue-73976-polymorphic.stderr
@@ -1,4 +1,4 @@
-error[E0158]: constant pattern depends on a generic parameter, which is not allowed
+error[E0158]: constant pattern cannot depend on generic parameters
   --> $DIR/issue-73976-polymorphic.rs:20:37
    |
 LL | impl<T: 'static> GetTypeId<T> {
@@ -7,11 +7,11 @@ LL |     pub const VALUE: TypeId = TypeId::of::<T>();
    |     ----------------------- constant defined here
 ...
 LL | const fn check_type_id<T: 'static>() -> bool {
-   |                        - constant depends on this generic param
+   |                        - constant depends on this generic parameter
 LL |     matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
    |                                     ^^^^^^^^^^^^^^^^^^^^^ `const` depends on a generic parameter
 
-error[E0158]: constant pattern depends on a generic parameter, which is not allowed
+error[E0158]: constant pattern cannot depend on generic parameters
   --> $DIR/issue-73976-polymorphic.rs:31:42
    |
 LL | impl<T: 'static> GetTypeNameLen<T> {
@@ -20,7 +20,7 @@ LL |     pub const VALUE: usize = any::type_name::<T>().len();
    |     ---------------------- constant defined here
 ...
 LL | const fn check_type_name_len<T: 'static>() -> bool {
-   |                              - constant depends on this generic param
+   |                              - constant depends on this generic parameter
 LL |     matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^ `const` depends on a generic parameter
 
diff --git a/tests/ui/consts/issue-79137-toogeneric.rs b/tests/ui/consts/issue-79137-toogeneric.rs
index a80c9f48d7bc9..43e06f3d6766b 100644
--- a/tests/ui/consts/issue-79137-toogeneric.rs
+++ b/tests/ui/consts/issue-79137-toogeneric.rs
@@ -10,7 +10,7 @@ impl<T> GetVariantCount<T> {
 
 const fn check_variant_count<T>() -> bool {
     matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE)
-    //~^ ERROR constant pattern depends on a generic parameter
+    //~^ ERROR constant pattern cannot depend on generic parameters
 }
 
 fn main() {
diff --git a/tests/ui/consts/issue-79137-toogeneric.stderr b/tests/ui/consts/issue-79137-toogeneric.stderr
index d36f3ecbb7690..33e32a7d15dca 100644
--- a/tests/ui/consts/issue-79137-toogeneric.stderr
+++ b/tests/ui/consts/issue-79137-toogeneric.stderr
@@ -1,4 +1,4 @@
-error[E0158]: constant pattern depends on a generic parameter, which is not allowed
+error[E0158]: constant pattern cannot depend on generic parameters
   --> $DIR/issue-79137-toogeneric.rs:12:43
    |
 LL | impl<T> GetVariantCount<T> {
@@ -7,7 +7,7 @@ LL |     pub const VALUE: usize = std::mem::variant_count::<T>();
    |     ---------------------- constant defined here
 ...
 LL | const fn check_variant_count<T>() -> bool {
-   |                              - constant depends on this generic param
+   |                              - constant depends on this generic parameter
 LL |     matches!(GetVariantCount::<T>::VALUE, GetVariantCount::<T>::VALUE)
    |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `const` depends on a generic parameter
 
diff --git a/tests/ui/inline-const/const-match-pat-generic.rs b/tests/ui/inline-const/const-match-pat-generic.rs
index 9d76fc2ad65bc..889c015e9acb3 100644
--- a/tests/ui/inline-const/const-match-pat-generic.rs
+++ b/tests/ui/inline-const/const-match-pat-generic.rs
@@ -5,7 +5,7 @@
 fn foo<const V: usize>() {
     match 0 {
         const { V } => {},
-        //~^ ERROR constant pattern depends on a generic parameter
+        //~^ ERROR constant pattern cannot depend on generic parameters
         _ => {},
     }
 }
@@ -17,7 +17,7 @@ const fn f(x: usize) -> usize {
 fn bar<const V: usize>() {
     match 0 {
         const { f(V) } => {},
-        //~^ ERROR constant pattern depends on a generic parameter
+        //~^ ERROR constant pattern cannot depend on generic parameters
         _ => {},
     }
 }
diff --git a/tests/ui/inline-const/const-match-pat-generic.stderr b/tests/ui/inline-const/const-match-pat-generic.stderr
index cf48161b5e3d6..7d9e1d9e407e1 100644
--- a/tests/ui/inline-const/const-match-pat-generic.stderr
+++ b/tests/ui/inline-const/const-match-pat-generic.stderr
@@ -1,10 +1,10 @@
-error[E0158]: constant pattern depends on a generic parameter, which is not allowed
+error[E0158]: constant pattern cannot depend on generic parameters
   --> $DIR/const-match-pat-generic.rs:7:9
    |
 LL |         const { V } => {},
    |         ^^^^^^^^^^^ `const` depends on a generic parameter
 
-error[E0158]: constant pattern depends on a generic parameter, which is not allowed
+error[E0158]: constant pattern cannot depend on generic parameters
   --> $DIR/const-match-pat-generic.rs:19:9
    |
 LL |         const { f(V) } => {},

From 03aec5dbef301219a288c46401d2bf0079724929 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sat, 16 Nov 2024 19:00:28 +0000
Subject: [PATCH 21/21] fn_sig_for_fn_abi should return a ty::FnSig, no need
 for a binder

---
 compiler/rustc_mir_transform/src/shim.rs |   4 +-
 compiler/rustc_ty_utils/src/abi.rs       | 130 +++++++++--------------
 2 files changed, 52 insertions(+), 82 deletions(-)

diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 809357ec11009..b8383e734e2ba 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -747,8 +747,8 @@ fn build_call_shim<'tcx>(
         sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
     }
 
-    // FIXME(eddyb) avoid having this snippet both here and in
-    // `Instance::fn_sig` (introduce `InstanceKind::fn_sig`?).
+    // FIXME: Avoid having to adjust the signature both here and in
+    // `fn_sig_for_fn_abi`.
     if let ty::InstanceKind::VTableShim(..) = instance {
         // Modify fn(self, ...) to fn(self: *mut Self, ...)
         let mut inputs_and_output = sig.inputs_and_output.to_vec();
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index a5a9125c8b509..b746d6299efda 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -31,20 +31,20 @@ fn fn_sig_for_fn_abi<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: ty::Instance<'tcx>,
     typing_env: ty::TypingEnv<'tcx>,
-) -> ty::PolyFnSig<'tcx> {
+) -> ty::FnSig<'tcx> {
     if let InstanceKind::ThreadLocalShim(..) = instance.def {
-        return ty::Binder::dummy(tcx.mk_fn_sig(
+        return tcx.mk_fn_sig(
             [],
             tcx.thread_local_ptr_ty(instance.def_id()),
             false,
             hir::Safety::Safe,
             rustc_abi::ExternAbi::Unadjusted,
-        ));
+        );
     }
 
     let ty = instance.ty(tcx, typing_env);
     match *ty.kind() {
-        ty::FnDef(..) => {
+        ty::FnDef(def_id, args) => {
             // HACK(davidtwco,eddyb): This is a workaround for polymorphization considering
             // parameters unused if they show up in the signature, but not in the `mir::Body`
             // (i.e. due to being inside a projection that got normalized, see
@@ -52,9 +52,8 @@ fn fn_sig_for_fn_abi<'tcx>(
             // track of a polymorphization `ParamEnv` to allow normalizing later.
             //
             // We normalize the `fn_sig` again after instantiating at a later point.
-            let mut sig = match *ty.kind() {
-                ty::FnDef(def_id, args) => tcx
-                    .fn_sig(def_id)
+            let mut sig = tcx.instantiate_bound_regions_with_erased(
+                tcx.fn_sig(def_id)
                     .map_bound(|fn_sig| {
                         tcx.normalize_erasing_regions(
                             ty::TypingEnv::non_body_analysis(tcx, def_id),
@@ -62,62 +61,36 @@ fn fn_sig_for_fn_abi<'tcx>(
                         )
                     })
                     .instantiate(tcx, args),
-                _ => unreachable!(),
-            };
+            );
 
             if let ty::InstanceKind::VTableShim(..) = instance.def {
-                // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`.
-                sig = sig.map_bound(|mut sig| {
-                    let mut inputs_and_output = sig.inputs_and_output.to_vec();
-                    inputs_and_output[0] = Ty::new_mut_ptr(tcx, inputs_and_output[0]);
-                    sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
-                    sig
-                });
+                let mut inputs_and_output = sig.inputs_and_output.to_vec();
+                inputs_and_output[0] = Ty::new_mut_ptr(tcx, inputs_and_output[0]);
+                sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
             }
+
             sig
         }
         ty::Closure(def_id, args) => {
-            let sig = args.as_closure().sig();
-
-            let bound_vars =
-                tcx.mk_bound_variable_kinds_from_iter(sig.bound_vars().iter().chain(iter::once(
-                    ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv),
-                )));
-            let br = ty::BoundRegion {
-                var: ty::BoundVar::from_usize(bound_vars.len() - 1),
-                kind: ty::BoundRegionKind::ClosureEnv,
-            };
-            let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br);
+            let sig = tcx.instantiate_bound_regions_with_erased(args.as_closure().sig());
             let env_ty = tcx.closure_env_ty(
                 Ty::new_closure(tcx, def_id, args),
                 args.as_closure().kind(),
-                env_region,
+                tcx.lifetimes.re_erased,
             );
 
-            let sig = sig.skip_binder();
-            ty::Binder::bind_with_vars(
-                tcx.mk_fn_sig(
-                    iter::once(env_ty).chain(sig.inputs().iter().cloned()),
-                    sig.output(),
-                    sig.c_variadic,
-                    sig.safety,
-                    sig.abi,
-                ),
-                bound_vars,
+            tcx.mk_fn_sig(
+                iter::once(env_ty).chain(sig.inputs().iter().cloned()),
+                sig.output(),
+                sig.c_variadic,
+                sig.safety,
+                sig.abi,
             )
         }
         ty::CoroutineClosure(def_id, args) => {
             let coroutine_ty = Ty::new_coroutine_closure(tcx, def_id, args);
             let sig = args.as_coroutine_closure().coroutine_closure_sig();
-            let bound_vars =
-                tcx.mk_bound_variable_kinds_from_iter(sig.bound_vars().iter().chain(iter::once(
-                    ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv),
-                )));
-            let br = ty::BoundRegion {
-                var: ty::BoundVar::from_usize(bound_vars.len() - 1),
-                kind: ty::BoundRegionKind::ClosureEnv,
-            };
-            let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br);
+
             // When this `CoroutineClosure` comes from a `ConstructCoroutineInClosureShim`,
             // make sure we respect the `target_kind` in that shim.
             // FIXME(async_closures): This shouldn't be needed, and we should be populating
@@ -138,42 +111,32 @@ fn fn_sig_for_fn_abi<'tcx>(
                         coroutine_ty
                     }
                 } else {
-                    tcx.closure_env_ty(coroutine_ty, coroutine_kind, env_region)
+                    tcx.closure_env_ty(coroutine_ty, coroutine_kind, tcx.lifetimes.re_erased)
                 };
 
-            let sig = sig.skip_binder();
-            ty::Binder::bind_with_vars(
-                tcx.mk_fn_sig(
-                    iter::once(env_ty).chain([sig.tupled_inputs_ty]),
-                    sig.to_coroutine_given_kind_and_upvars(
-                        tcx,
-                        args.as_coroutine_closure().parent_args(),
-                        tcx.coroutine_for_closure(def_id),
-                        coroutine_kind,
-                        env_region,
-                        args.as_coroutine_closure().tupled_upvars_ty(),
-                        args.as_coroutine_closure().coroutine_captures_by_ref_ty(),
-                    ),
-                    sig.c_variadic,
-                    sig.safety,
-                    sig.abi,
+            let sig = tcx.instantiate_bound_regions_with_erased(sig);
+
+            tcx.mk_fn_sig(
+                iter::once(env_ty).chain([sig.tupled_inputs_ty]),
+                sig.to_coroutine_given_kind_and_upvars(
+                    tcx,
+                    args.as_coroutine_closure().parent_args(),
+                    tcx.coroutine_for_closure(def_id),
+                    coroutine_kind,
+                    tcx.lifetimes.re_erased,
+                    args.as_coroutine_closure().tupled_upvars_ty(),
+                    args.as_coroutine_closure().coroutine_captures_by_ref_ty(),
                 ),
-                bound_vars,
+                sig.c_variadic,
+                sig.safety,
+                sig.abi,
             )
         }
         ty::Coroutine(did, args) => {
             let coroutine_kind = tcx.coroutine_kind(did).unwrap();
             let sig = args.as_coroutine().sig();
 
-            let bound_vars = tcx.mk_bound_variable_kinds_from_iter(iter::once(
-                ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv),
-            ));
-            let br = ty::BoundRegion {
-                var: ty::BoundVar::from_usize(bound_vars.len() - 1),
-                kind: ty::BoundRegionKind::ClosureEnv,
-            };
-
-            let env_ty = Ty::new_mut_ref(tcx, ty::Region::new_bound(tcx, ty::INNERMOST, br), ty);
+            let env_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, ty);
 
             let pin_did = tcx.require_lang_item(LangItem::Pin, None);
             let pin_adt_ref = tcx.adt_def(pin_did);
@@ -268,7 +231,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                 }
             };
 
-            let fn_sig = if let Some(resume_ty) = resume_ty {
+            if let Some(resume_ty) = resume_ty {
                 tcx.mk_fn_sig(
                     [env_ty, resume_ty],
                     ret_ty,
@@ -285,8 +248,7 @@ fn fn_sig_for_fn_abi<'tcx>(
                     hir::Safety::Safe,
                     rustc_abi::ExternAbi::Rust,
                 )
-            };
-            ty::Binder::bind_with_vars(fn_sig, bound_vars)
+            }
         }
         _ => bug!("unexpected type {:?} in Instance::fn_sig", ty),
     }
@@ -335,8 +297,16 @@ fn fn_abi_of_fn_ptr<'tcx>(
     query: ty::PseudoCanonicalInput<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
 ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
     let ty::PseudoCanonicalInput { typing_env, value: (sig, extra_args) } = query;
+
     let cx = LayoutCx::new(tcx, typing_env);
-    fn_abi_new_uncached(&cx, sig, extra_args, None, None, false)
+    fn_abi_new_uncached(
+        &cx,
+        tcx.instantiate_bound_regions_with_erased(sig),
+        extra_args,
+        None,
+        None,
+        false,
+    )
 }
 
 fn fn_abi_of_instance<'tcx>(
@@ -567,7 +537,7 @@ fn fn_abi_sanity_check<'tcx>(
 #[tracing::instrument(level = "debug", skip(cx, caller_location, fn_def_id, force_thin_self_ptr))]
 fn fn_abi_new_uncached<'tcx>(
     cx: &LayoutCx<'tcx>,
-    sig: ty::PolyFnSig<'tcx>,
+    sig: ty::FnSig<'tcx>,
     extra_args: &[Ty<'tcx>],
     caller_location: Option<Ty<'tcx>>,
     fn_def_id: Option<DefId>,
@@ -575,7 +545,7 @@ fn fn_abi_new_uncached<'tcx>(
     force_thin_self_ptr: bool,
 ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
     let tcx = cx.tcx();
-    let sig = tcx.normalize_erasing_late_bound_regions(cx.typing_env, sig);
+    let sig = tcx.normalize_erasing_regions(cx.typing_env, sig);
 
     let conv = conv_from_spec_abi(cx.tcx(), sig.abi, sig.c_variadic);