From 26c4893ae6a6bd5d611fd6c7b3c803a720138d40 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gabriel=20Bj=C3=B8rnager=20Jensen?= <gabriel@achernar.io>
Date: Tue, 24 Sep 2024 22:40:29 +0200
Subject: [PATCH 01/16] Mark 'get_mut' and 'set_position' in 'std::io::Cursor'
 as const;

---
 library/std/src/io/cursor.rs | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index 9f913eae09544..fbfdb4fa02323 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -153,7 +153,8 @@ impl<T> Cursor<T> {
     /// let reference = buff.get_mut();
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_mut(&mut self) -> &mut T {
+    #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")]
+    pub const fn get_mut(&mut self) -> &mut T {
         &mut self.inner
     }
 
@@ -200,7 +201,8 @@ impl<T> Cursor<T> {
     /// assert_eq!(buff.position(), 4);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn set_position(&mut self, pos: u64) {
+    #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")]
+    pub const fn set_position(&mut self, pos: u64) {
         self.pos = pos;
     }
 }

From 3727a8c4d8169043a40f327dbd39db0c4448aef6 Mon Sep 17 00:00:00 2001
From: Ayush Singh <ayush@beagleboard.org>
Date: Sun, 1 Sep 2024 04:20:20 +0530
Subject: [PATCH 02/16] uefi: process: Add args support

- Wrap all args with quotes.
- Escape ^ and " inside quotes using ^.

Signed-off-by: Ayush Singh <ayush@beagleboard.org>
---
 library/std/src/sys/pal/uefi/process.rs | 68 ++++++++++++++++++++-----
 1 file changed, 56 insertions(+), 12 deletions(-)

diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs
index fdc5f5d7e4fea..4494b3df57bdd 100644
--- a/library/std/src/sys/pal/uefi/process.rs
+++ b/library/std/src/sys/pal/uefi/process.rs
@@ -18,6 +18,7 @@ use crate::{fmt, io};
 #[derive(Debug)]
 pub struct Command {
     prog: OsString,
+    args: Vec<OsString>,
     stdout: Option<Stdio>,
     stderr: Option<Stdio>,
 }
@@ -39,12 +40,11 @@ pub enum Stdio {
 
 impl Command {
     pub fn new(program: &OsStr) -> Command {
-        Command { prog: program.to_os_string(), stdout: None, stderr: None }
+        Command { prog: program.to_os_string(), args: Vec::new(), stdout: None, stderr: None }
     }
 
-    // FIXME: Implement arguments as reverse of parsing algorithm
-    pub fn arg(&mut self, _arg: &OsStr) {
-        panic!("unsupported")
+    pub fn arg(&mut self, arg: &OsStr) {
+        self.args.push(arg.to_os_string());
     }
 
     pub fn env_mut(&mut self) -> &mut CommandEnv {
@@ -72,7 +72,7 @@ impl Command {
     }
 
     pub fn get_args(&self) -> CommandArgs<'_> {
-        panic!("unsupported")
+        CommandArgs { iter: self.args.iter() }
     }
 
     pub fn get_envs(&self) -> CommandEnvs<'_> {
@@ -116,6 +116,12 @@ impl Command {
     pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
         let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;
 
+        // UEFI adds the bin name by default
+        if !self.args.is_empty() {
+            let args = uefi_command_internal::create_args(&self.prog, &self.args);
+            cmd.set_args(args);
+        }
+
         // Setup Stdout
         let stdout = self.stdout.unwrap_or(Stdio::MakePipe);
         let stdout = Self::create_pipe(stdout)?;
@@ -315,7 +321,7 @@ mod uefi_command_internal {
         stdout: Option<helpers::OwnedProtocol<PipeProtocol>>,
         stderr: Option<helpers::OwnedProtocol<PipeProtocol>>,
         st: OwnedTable<r_efi::efi::SystemTable>,
-        args: Option<Vec<u16>>,
+        args: Option<(*mut u16, usize)>,
     }
 
     impl Image {
@@ -449,20 +455,20 @@ mod uefi_command_internal {
             }
         }
 
-        pub fn set_args(&mut self, args: &OsStr) {
+        pub fn set_args(&mut self, args: Box<[u16]>) {
             let loaded_image: NonNull<loaded_image::Protocol> =
                 helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap();
 
-            let mut args = args.encode_wide().collect::<Vec<u16>>();
-            let args_size = (crate::mem::size_of::<u16>() * args.len()) as u32;
+            let len = args.len();
+            let args_size: u32 = crate::mem::size_of_val(&args).try_into().unwrap();
+            let ptr = Box::into_raw(args).as_mut_ptr();
 
             unsafe {
-                (*loaded_image.as_ptr()).load_options =
-                    args.as_mut_ptr() as *mut crate::ffi::c_void;
+                (*loaded_image.as_ptr()).load_options = ptr as *mut crate::ffi::c_void;
                 (*loaded_image.as_ptr()).load_options_size = args_size;
             }
 
-            self.args = Some(args);
+            self.args = Some((ptr, len));
         }
 
         fn update_st_crc32(&mut self) -> io::Result<()> {
@@ -502,6 +508,10 @@ mod uefi_command_internal {
                     ((*bt.as_ptr()).unload_image)(self.handle.as_ptr());
                 }
             }
+
+            if let Some((ptr, len)) = self.args {
+                let _ = unsafe { Box::from_raw(crate::ptr::slice_from_raw_parts_mut(ptr, len)) };
+            }
         }
     }
 
@@ -681,4 +691,38 @@ mod uefi_command_internal {
             }
         }
     }
+
+    pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> {
+        const QUOTE: u16 = 0x0022;
+        const SPACE: u16 = 0x0020;
+        const CARET: u16 = 0x005e;
+        const NULL: u16 = 0;
+
+        // This is the lower bound on the final length under the assumption that
+        // the arguments only contain ASCII characters.
+        let mut res = Vec::with_capacity(args.iter().map(|arg| arg.len() + 3).sum());
+
+        // Wrap program name in quotes to avoid any problems
+        res.push(QUOTE);
+        res.extend(prog.encode_wide());
+        res.push(QUOTE);
+        res.push(SPACE);
+
+        for arg in args {
+            // Wrap the argument in quotes to be treat as single arg
+            res.push(QUOTE);
+            for c in arg.encode_wide() {
+                // CARET in quotes is used to escape CARET or QUOTE
+                if c == QUOTE || c == CARET {
+                    res.push(CARET);
+                }
+                res.push(c);
+            }
+            res.push(QUOTE);
+
+            res.push(SPACE);
+        }
+
+        res.into_boxed_slice()
+    }
 }

From ff2f7a7a834843ea74b1e7d6511eb4ad06f43981 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 6 Nov 2024 19:46:54 +0000
Subject: [PATCH 03/16] Point at `const` definition when used instead of a
 binding in a `let` statement

After:

```
error[E0005]: refutable pattern in local binding
  --> $DIR/bad-pattern.rs:19:13
   |
LL |     const PAT: u32 = 0;
   |     -------------- missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable
...
LL |         let PAT = v1;
   |             ^^^
   |             |
   |             pattern `1_u32..=u32::MAX` not covered
   |             help: introduce a variable instead: `PAT_var`
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
   = note: the matched value is of type `u32`
```

Before:

```
error[E0005]: refutable pattern in local binding
  --> $DIR/bad-pattern.rs:19:13
   |
LL |         let PAT = v1;
   |             ^^^
   |             |
   |             pattern `1_u32..=u32::MAX` not covered
   |             missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable
   |             help: introduce a variable instead: `PAT_var`
   |
   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
   = note: the matched value is of type `u32`
```
---
 compiler/rustc_middle/src/thir.rs              | 11 +++++++++--
 compiler/rustc_middle/src/thir/visit.rs        |  2 +-
 .../src/build/custom/parse/instruction.rs      |  4 +++-
 .../src/build/matches/match_pair.rs            |  4 +++-
 .../rustc_mir_build/src/build/matches/mod.rs   |  1 +
 compiler/rustc_mir_build/src/check_unsafety.rs |  1 +
 compiler/rustc_mir_build/src/errors.rs         |  5 +++--
 .../src/thir/pattern/check_match.rs            | 18 ++++++++++++++++--
 .../rustc_mir_build/src/thir/pattern/mod.rs    | 12 ++++++++++--
 compiler/rustc_mir_build/src/thir/print.rs     |  2 +-
 compiler/rustc_pattern_analysis/src/rustc.rs   |  2 +-
 compiler/rustc_ty_utils/src/consts.rs          |  4 +++-
 .../2229_closure_analysis/bad-pattern.stderr   |  4 +++-
 tests/ui/consts/const-pattern-irrefutable.rs   |  6 +++---
 .../ui/consts/const-pattern-irrefutable.stderr | 18 ++++++++++++------
 tests/ui/mir/issue-112269.stderr               |  6 ++++--
 .../const-pat-non-exaustive-let-new-var.rs     |  2 +-
 .../const-pat-non-exaustive-let-new-var.stderr |  4 +++-
 18 files changed, 78 insertions(+), 28 deletions(-)

diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 45ceb0a555d33..821f8c9970448 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -640,6 +640,7 @@ impl<'tcx> Pat<'tcx> {
             | Range(..)
             | Binding { subpattern: None, .. }
             | Constant { .. }
+            | NamedConstant { .. }
             | Error(_) => {}
             AscribeUserType { subpattern, .. }
             | Binding { subpattern: Some(subpattern), .. }
@@ -788,6 +789,12 @@ pub enum PatKind<'tcx> {
         value: mir::Const<'tcx>,
     },
 
+    /// Same as `Constant`, but that came from a `const` that we can point at in diagnostics.
+    NamedConstant {
+        value: mir::Const<'tcx>,
+        span: Span,
+    },
+
     /// Inline constant found while lowering a pattern.
     InlineConstant {
         /// [LocalDefId] of the constant, we need this so that we have a
@@ -1084,8 +1091,8 @@ mod size_asserts {
     static_assert_size!(Block, 48);
     static_assert_size!(Expr<'_>, 64);
     static_assert_size!(ExprKind<'_>, 40);
-    static_assert_size!(Pat<'_>, 64);
-    static_assert_size!(PatKind<'_>, 48);
+    static_assert_size!(Pat<'_>, 72);
+    static_assert_size!(PatKind<'_>, 56);
     static_assert_size!(Stmt<'_>, 48);
     static_assert_size!(StmtKind<'_>, 48);
     // tidy-alphabetical-end
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 36f0e3d890cfd..759ed77dbcbb2 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -246,7 +246,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
                 visitor.visit_pat(&subpattern.pattern);
             }
         }
-        Constant { value: _ } => {}
+        Constant { value: _ } | NamedConstant { value: _, span: _ } => {}
         InlineConstant { def: _, subpattern } => visitor.visit_pat(subpattern),
         Range(_) => {}
         Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index 07964e304b9ed..049586fd6a0b7 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -144,7 +144,9 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
         let mut targets = Vec::new();
         for arm in rest {
             let arm = &self.thir[*arm];
-            let PatKind::Constant { value } = arm.pattern.kind else {
+            let (PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ }) =
+                arm.pattern.kind
+            else {
                 return Err(ParseError {
                     span: arm.pattern.span,
                     item_description: format!("{:?}", arm.pattern.kind),
diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
index 6df50057ee83a..83a1e02148408 100644
--- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
@@ -129,7 +129,9 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
                 }
             }
 
-            PatKind::Constant { value } => TestCase::Constant { value },
+            PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ } => {
+                TestCase::Constant { value }
+            }
 
             PatKind::AscribeUserType {
                 ascription: thir::Ascription { ref annotation, variance },
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index a62d4e9d87373..ac5be6656542d 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -882,6 +882,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
 
             PatKind::Constant { .. }
+            | PatKind::NamedConstant { .. }
             | PatKind::Range { .. }
             | PatKind::Wild
             | PatKind::Never
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 33e194fa2462a..d073cbdd87736 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -316,6 +316,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 PatKind::Binding { .. }
                 // match is conditional on having this value
                 | PatKind::Constant { .. }
+                | PatKind::NamedConstant { .. }
                 | PatKind::Variant { .. }
                 | PatKind::Leaf { .. }
                 | PatKind::Deref { .. }
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 00f65e0c7d093..04eb7ffe77650 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -860,8 +860,10 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
     pub(crate) uncovered: Uncovered,
     #[subdiagnostic]
     pub(crate) inform: Option<Inform>,
+    #[label(mir_build_confused)]
+    pub(crate) interpreted_as_const: Option<Span>,
     #[subdiagnostic]
-    pub(crate) interpreted_as_const: Option<InterpretedAsConst>,
+    pub(crate) interpreted_as_const_sugg: Option<InterpretedAsConst>,
     #[subdiagnostic]
     pub(crate) adt_defined_here: Option<AdtDefinedHere<'tcx>>,
     #[note(mir_build_privately_uninhabited)]
@@ -913,7 +915,6 @@ impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> {
     code = "{variable}_var",
     applicability = "maybe-incorrect"
 )]
-#[label(mir_build_confused)]
 pub(crate) struct InterpretedAsConst {
     #[primary_span]
     pub(crate) span: Span,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index f222a869c0344..b54e1c2b5524d 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -668,8 +668,20 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
         let mut let_suggestion = None;
         let mut misc_suggestion = None;
         let mut interpreted_as_const = None;
+        let mut interpreted_as_const_sugg = None;
 
-        if let PatKind::Constant { .. }
+        if let PatKind::NamedConstant { span, .. }
+        | PatKind::AscribeUserType {
+            subpattern: box Pat { kind: PatKind::NamedConstant { span, .. }, .. },
+            ..
+        } = pat.kind
+            && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
+        {
+            // When we encounter a constant as the binding name, point at the `const` definition.
+            interpreted_as_const = Some(span);
+            interpreted_as_const_sugg =
+                Some(InterpretedAsConst { span: pat.span, variable: snippet });
+        } else if let PatKind::Constant { .. }
         | PatKind::AscribeUserType {
             subpattern: box Pat { kind: PatKind::Constant { .. }, .. },
             ..
@@ -683,7 +695,8 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
                     start_span: pat.span.shrink_to_lo(),
                 });
             } else if snippet.chars().all(|c| c.is_alphanumeric() || c == '_') {
-                interpreted_as_const =
+                interpreted_as_const = Some(pat.span);
+                interpreted_as_const_sugg =
                     Some(InterpretedAsConst { span: pat.span, variable: snippet });
             }
         }
@@ -733,6 +746,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             uncovered: Uncovered::new(pat.span, &cx, witnesses),
             inform,
             interpreted_as_const,
+            interpreted_as_const_sugg,
             witness_1_is_privately_uninhabited,
             _p: (),
             pattern_ty,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index ec852add94db7..260ace55fba69 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -157,7 +157,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     }
                     kind => (kind, None, None),
                 };
-                let value = if let PatKind::Constant { value } = kind {
+                let value = if let PatKind::Constant { value }
+                | PatKind::NamedConstant { value, span: _ } = kind
+                {
                     value
                 } else {
                     let msg = format!(
@@ -560,9 +562,15 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             _ => return pat_from_kind(self.lower_variant_or_leaf(res, id, span, ty, vec![])),
         };
 
+        // HERE
         let args = self.typeck_results.node_args(id);
         let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
-        let pattern = self.const_to_pat(c, ty, id, span);
+        let def_span = self.tcx.def_span(def_id);
+        let mut pattern = self.const_to_pat(c, ty, id, span);
+        if let PatKind::Constant { value } = pattern.kind {
+            pattern.kind = PatKind::NamedConstant { value, span: def_span };
+        }
+        tracing::info!("pattern {pattern:#?} {c:?} {ty:?} {id:?}");
 
         if !is_associated_const {
             return pattern;
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index dae13df4054a4..3fe75439339d9 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -702,7 +702,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
                 self.print_pat(subpattern, depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
             }
-            PatKind::Constant { value } => {
+            PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ } => {
                 print_indented!(self, "Constant {", depth_lvl + 1);
                 print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 9ea5023064c1c..6496d9fd73d27 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -536,7 +536,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                     ),
                 }
             }
-            PatKind::Constant { value } => {
+            PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ } => {
                 match ty.kind() {
                     ty::Bool => {
                         ctor = match value.try_eval_bool(cx.tcx, cx.param_env) {
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index 637e239a57010..3a0eb8143cd53 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -370,7 +370,9 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
         }
 
         match pat.kind {
-            thir::PatKind::Constant { value } => value.has_non_region_param(),
+            thir::PatKind::Constant { value } | thir::PatKind::NamedConstant { value, span: _ } => {
+                value.has_non_region_param()
+            }
             thir::PatKind::Range(box thir::PatRange { lo, hi, .. }) => {
                 lo.has_non_region_param() || hi.has_non_region_param()
             }
diff --git a/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr b/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr
index ca8c2a16d323f..5692d530b0698 100644
--- a/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr
+++ b/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr
@@ -97,11 +97,13 @@ LL |         if let Refutable::A = v3 { todo!() };
 error[E0005]: refutable pattern in local binding
   --> $DIR/bad-pattern.rs:19:13
    |
+LL |     const PAT: u32 = 0;
+   |     -------------- missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable
+...
 LL |         let PAT = v1;
    |             ^^^
    |             |
    |             pattern `1_u32..=u32::MAX` not covered
-   |             missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable
    |             help: introduce a variable instead: `PAT_var`
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
diff --git a/tests/ui/consts/const-pattern-irrefutable.rs b/tests/ui/consts/const-pattern-irrefutable.rs
index 61bdf57ffdb94..54d2ad323860d 100644
--- a/tests/ui/consts/const-pattern-irrefutable.rs
+++ b/tests/ui/consts/const-pattern-irrefutable.rs
@@ -1,28 +1,28 @@
 mod foo {
     pub const b: u8 = 2;
+    //~^ missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
     pub const d: u8 = 2;
+    //~^ missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
 }
 
 use foo::b as c;
 use foo::d;
 
 const a: u8 = 2;
+//~^ missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
 
 fn main() {
     let a = 4;
     //~^ ERROR refutable pattern in local binding
     //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-    //~| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
     //~| HELP introduce a variable instead
     let c = 4;
     //~^ ERROR refutable pattern in local binding
     //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-    //~| missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
     //~| HELP introduce a variable instead
     let d = 4;
     //~^ ERROR refutable pattern in local binding
     //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-    //~| missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
     //~| HELP introduce a variable instead
     fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115).
 }
diff --git a/tests/ui/consts/const-pattern-irrefutable.stderr b/tests/ui/consts/const-pattern-irrefutable.stderr
index 2aed68bdd6433..d4365fa16e8e4 100644
--- a/tests/ui/consts/const-pattern-irrefutable.stderr
+++ b/tests/ui/consts/const-pattern-irrefutable.stderr
@@ -1,11 +1,13 @@
 error[E0005]: refutable pattern in local binding
-  --> $DIR/const-pattern-irrefutable.rs:12:9
+  --> $DIR/const-pattern-irrefutable.rs:15:9
    |
+LL | const a: u8 = 2;
+   | ----------- missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
+...
 LL |     let a = 4;
    |         ^
    |         |
    |         patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-   |         missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
    |         help: introduce a variable instead: `a_var`
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
@@ -13,13 +15,15 @@ LL |     let a = 4;
    = note: the matched value is of type `u8`
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/const-pattern-irrefutable.rs:17:9
+  --> $DIR/const-pattern-irrefutable.rs:19:9
    |
+LL |     pub const b: u8 = 2;
+   |     --------------- missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
+...
 LL |     let c = 4;
    |         ^
    |         |
    |         patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-   |         missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
    |         help: introduce a variable instead: `c_var`
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
@@ -27,13 +31,15 @@ LL |     let c = 4;
    = note: the matched value is of type `u8`
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/const-pattern-irrefutable.rs:22:9
+  --> $DIR/const-pattern-irrefutable.rs:23:9
    |
+LL |     pub const d: u8 = 2;
+   |     --------------- missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
+...
 LL |     let d = 4;
    |         ^
    |         |
    |         patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-   |         missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
    |         help: introduce a variable instead: `d_var`
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
diff --git a/tests/ui/mir/issue-112269.stderr b/tests/ui/mir/issue-112269.stderr
index f5b796027979c..945a7e25dd0e3 100644
--- a/tests/ui/mir/issue-112269.stderr
+++ b/tests/ui/mir/issue-112269.stderr
@@ -1,11 +1,12 @@
 error[E0005]: refutable pattern in local binding
   --> $DIR/issue-112269.rs:3:9
    |
+LL |     const x: i32 = 4;
+   |     ------------ missing patterns are not covered because `x` is interpreted as a constant pattern, not a new variable
 LL |     let x: i32 = 3;
    |         ^
    |         |
    |         patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
-   |         missing patterns are not covered because `x` is interpreted as a constant pattern, not a new variable
    |         help: introduce a variable instead: `x_var`
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
@@ -15,11 +16,12 @@ LL |     let x: i32 = 3;
 error[E0005]: refutable pattern in local binding
   --> $DIR/issue-112269.rs:7:9
    |
+LL |     const y: i32 = 3;
+   |     ------------ missing patterns are not covered because `y` is interpreted as a constant pattern, not a new variable
 LL |     let y = 4;
    |         ^
    |         |
    |         patterns `i32::MIN..=2_i32` and `4_i32..=i32::MAX` not covered
-   |         missing patterns are not covered because `y` is interpreted as a constant pattern, not a new variable
    |         help: introduce a variable instead: `y_var`
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
index af47ba8baa3fe..1a440a90cd734 100644
--- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
+++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
@@ -2,9 +2,9 @@ fn main() {
     let A = 3;
     //~^ ERROR refutable pattern in local binding
     //~| patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
-    //~| missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
     //~| HELP introduce a variable instead
     //~| SUGGESTION A_var
 
     const A: i32 = 2;
+    //~^ missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
 }
diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
index b6c286128023d..29c4b2905ebd9 100644
--- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
+++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
@@ -5,8 +5,10 @@ LL |     let A = 3;
    |         ^
    |         |
    |         patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
-   |         missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
    |         help: introduce a variable instead: `A_var`
+...
+LL |     const A: i32 = 2;
+   |     ------------ missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html

From c25b44bee96e4489dab8f44409ba347bfeb328b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 6 Nov 2024 21:10:31 +0000
Subject: [PATCH 04/16] Fold `PatKind::NamedConstant` into `PatKind::Constant`

---
 compiler/rustc_middle/src/thir.rs                   |  9 ++-------
 compiler/rustc_middle/src/thir/visit.rs             |  2 +-
 .../src/build/custom/parse/instruction.rs           |  4 +---
 .../rustc_mir_build/src/build/matches/match_pair.rs |  4 +---
 compiler/rustc_mir_build/src/build/matches/mod.rs   |  1 -
 compiler/rustc_mir_build/src/check_unsafety.rs      |  1 -
 .../rustc_mir_build/src/thir/pattern/check_match.rs |  5 +++--
 .../src/thir/pattern/const_to_pat.rs                |  7 ++++++-
 compiler/rustc_mir_build/src/thir/pattern/mod.rs    | 13 ++++---------
 compiler/rustc_mir_build/src/thir/print.rs          |  2 +-
 compiler/rustc_pattern_analysis/src/rustc.rs        |  2 +-
 compiler/rustc_ty_utils/src/consts.rs               |  4 +---
 12 files changed, 21 insertions(+), 33 deletions(-)

diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 821f8c9970448..84f5f3a461141 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -640,7 +640,6 @@ impl<'tcx> Pat<'tcx> {
             | Range(..)
             | Binding { subpattern: None, .. }
             | Constant { .. }
-            | NamedConstant { .. }
             | Error(_) => {}
             AscribeUserType { subpattern, .. }
             | Binding { subpattern: Some(subpattern), .. }
@@ -787,12 +786,8 @@ pub enum PatKind<'tcx> {
     /// * `String`, if `string_deref_patterns` is enabled.
     Constant {
         value: mir::Const<'tcx>,
-    },
-
-    /// Same as `Constant`, but that came from a `const` that we can point at in diagnostics.
-    NamedConstant {
-        value: mir::Const<'tcx>,
-        span: Span,
+        /// The `const` item this constant came from, if any.
+        opt_def: Option<DefId>,
     },
 
     /// Inline constant found while lowering a pattern.
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 759ed77dbcbb2..92c0add65bab7 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -246,7 +246,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
                 visitor.visit_pat(&subpattern.pattern);
             }
         }
-        Constant { value: _ } | NamedConstant { value: _, span: _ } => {}
+        Constant { value: _, opt_def: _ } => {}
         InlineConstant { def: _, subpattern } => visitor.visit_pat(subpattern),
         Range(_) => {}
         Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index 049586fd6a0b7..60624855fea99 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -144,9 +144,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
         let mut targets = Vec::new();
         for arm in rest {
             let arm = &self.thir[*arm];
-            let (PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ }) =
-                arm.pattern.kind
-            else {
+            let PatKind::Constant { value, opt_def: _ } = arm.pattern.kind else {
                 return Err(ParseError {
                     span: arm.pattern.span,
                     item_description: format!("{:?}", arm.pattern.kind),
diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
index 83a1e02148408..df3cf53eb1787 100644
--- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
@@ -129,9 +129,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
                 }
             }
 
-            PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ } => {
-                TestCase::Constant { value }
-            }
+            PatKind::Constant { value, opt_def: _ } => TestCase::Constant { value },
 
             PatKind::AscribeUserType {
                 ascription: thir::Ascription { ref annotation, variance },
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index ac5be6656542d..a62d4e9d87373 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -882,7 +882,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
 
             PatKind::Constant { .. }
-            | PatKind::NamedConstant { .. }
             | PatKind::Range { .. }
             | PatKind::Wild
             | PatKind::Never
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index d073cbdd87736..33e194fa2462a 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -316,7 +316,6 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 PatKind::Binding { .. }
                 // match is conditional on having this value
                 | PatKind::Constant { .. }
-                | PatKind::NamedConstant { .. }
                 | PatKind::Variant { .. }
                 | PatKind::Leaf { .. }
                 | PatKind::Deref { .. }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index b54e1c2b5524d..f3cfc8b1a2231 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -670,13 +670,14 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
         let mut interpreted_as_const = None;
         let mut interpreted_as_const_sugg = None;
 
-        if let PatKind::NamedConstant { span, .. }
+        if let PatKind::Constant { opt_def: Some(def_id), .. }
         | PatKind::AscribeUserType {
-            subpattern: box Pat { kind: PatKind::NamedConstant { span, .. }, .. },
+            subpattern: box Pat { kind: PatKind::Constant { opt_def: Some(def_id), .. }, .. },
             ..
         } = pat.kind
             && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
         {
+            let span = self.tcx.def_span(def_id);
             // When we encounter a constant as the binding name, point at the `const` definition.
             interpreted_as_const = Some(span);
             interpreted_as_const_sugg =
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 82632350af59c..06b13274efced 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
@@ -266,6 +266,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 // optimization for now.
                 ty::Str => PatKind::Constant {
                     value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)),
+                    opt_def: None,
                 },
                 // All other references are converted into deref patterns and then recursively
                 // convert the dereferenced constant to a pattern that is the sub-pattern of the
@@ -311,13 +312,17 @@ impl<'tcx> ConstToPat<'tcx> {
                 } else {
                     PatKind::Constant {
                         value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)),
+                        opt_def: None,
                     }
                 }
             }
             ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
                 // The raw pointers we see here have been "vetted" by valtree construction to be
                 // just integers, so we simply allow them.
-                PatKind::Constant { value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)) }
+                PatKind::Constant {
+                    value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)),
+                    opt_def: None,
+                }
             }
             ty::FnPtr(..) => {
                 unreachable!(
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 260ace55fba69..11d06e5a1cc03 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -157,9 +157,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     }
                     kind => (kind, None, None),
                 };
-                let value = if let PatKind::Constant { value }
-                | PatKind::NamedConstant { value, span: _ } = kind
-                {
+                let value = if let PatKind::Constant { value, opt_def: _ } = kind {
                     value
                 } else {
                     let msg = format!(
@@ -253,7 +251,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             (RangeEnd::Included, Some(Ordering::Less)) => {}
             // `x..=y` where `x == y` and `x` and `y` are finite.
             (RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => {
-                kind = PatKind::Constant { value: lo.as_finite().unwrap() };
+                kind = PatKind::Constant { value: lo.as_finite().unwrap(), opt_def: None };
             }
             // `..=x` where `x == ty::MIN`.
             (RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {}
@@ -562,15 +560,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             _ => return pat_from_kind(self.lower_variant_or_leaf(res, id, span, ty, vec![])),
         };
 
-        // HERE
         let args = self.typeck_results.node_args(id);
         let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
-        let def_span = self.tcx.def_span(def_id);
         let mut pattern = self.const_to_pat(c, ty, id, span);
-        if let PatKind::Constant { value } = pattern.kind {
-            pattern.kind = PatKind::NamedConstant { value, span: def_span };
+        if let PatKind::Constant { value, opt_def: None } = pattern.kind {
+            pattern.kind = PatKind::Constant { value, opt_def: Some(def_id) };
         }
-        tracing::info!("pattern {pattern:#?} {c:?} {ty:?} {id:?}");
 
         if !is_associated_const {
             return pattern;
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index 3fe75439339d9..43bca812bbd55 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -702,7 +702,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
                 self.print_pat(subpattern, depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
             }
-            PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ } => {
+            PatKind::Constant { value, opt_def: _ } => {
                 print_indented!(self, "Constant {", depth_lvl + 1);
                 print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 6496d9fd73d27..ec671150c40c7 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -536,7 +536,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                     ),
                 }
             }
-            PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ } => {
+            PatKind::Constant { value, opt_def: _ } => {
                 match ty.kind() {
                     ty::Bool => {
                         ctor = match value.try_eval_bool(cx.tcx, cx.param_env) {
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index 3a0eb8143cd53..12f169d718cc4 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -370,9 +370,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
         }
 
         match pat.kind {
-            thir::PatKind::Constant { value } | thir::PatKind::NamedConstant { value, span: _ } => {
-                value.has_non_region_param()
-            }
+            thir::PatKind::Constant { value, opt_def: _ } => value.has_non_region_param(),
             thir::PatKind::Range(box thir::PatRange { lo, hi, .. }) => {
                 lo.has_non_region_param() || hi.has_non_region_param()
             }

From 6dc79f6133d24100cecbcb24e256b9f149d2b47a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 6 Nov 2024 21:28:26 +0000
Subject: [PATCH 05/16] Use `item_name` instead of a span snippet when talking
 about const pattern

---
 compiler/rustc_mir_build/src/thir/pattern/check_match.rs | 5 ++---
 tests/ui/consts/const-pattern-irrefutable.rs             | 2 +-
 tests/ui/consts/const-pattern-irrefutable.stderr         | 4 ++--
 3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index f3cfc8b1a2231..a8830b346ae3c 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -675,13 +675,12 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             subpattern: box Pat { kind: PatKind::Constant { opt_def: Some(def_id), .. }, .. },
             ..
         } = pat.kind
-            && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
         {
             let span = self.tcx.def_span(def_id);
+            let variable = self.tcx.item_name(def_id).to_string();
             // When we encounter a constant as the binding name, point at the `const` definition.
             interpreted_as_const = Some(span);
-            interpreted_as_const_sugg =
-                Some(InterpretedAsConst { span: pat.span, variable: snippet });
+            interpreted_as_const_sugg = Some(InterpretedAsConst { span: pat.span, variable });
         } else if let PatKind::Constant { .. }
         | PatKind::AscribeUserType {
             subpattern: box Pat { kind: PatKind::Constant { .. }, .. },
diff --git a/tests/ui/consts/const-pattern-irrefutable.rs b/tests/ui/consts/const-pattern-irrefutable.rs
index 54d2ad323860d..c590ec8fcd361 100644
--- a/tests/ui/consts/const-pattern-irrefutable.rs
+++ b/tests/ui/consts/const-pattern-irrefutable.rs
@@ -1,6 +1,6 @@
 mod foo {
     pub const b: u8 = 2;
-    //~^ missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
+    //~^ missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable
     pub const d: u8 = 2;
     //~^ missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
 }
diff --git a/tests/ui/consts/const-pattern-irrefutable.stderr b/tests/ui/consts/const-pattern-irrefutable.stderr
index d4365fa16e8e4..c118ce9e48f2f 100644
--- a/tests/ui/consts/const-pattern-irrefutable.stderr
+++ b/tests/ui/consts/const-pattern-irrefutable.stderr
@@ -18,13 +18,13 @@ error[E0005]: refutable pattern in local binding
   --> $DIR/const-pattern-irrefutable.rs:19:9
    |
 LL |     pub const b: u8 = 2;
-   |     --------------- missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
+   |     --------------- missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable
 ...
 LL |     let c = 4;
    |         ^
    |         |
    |         patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-   |         help: introduce a variable instead: `c_var`
+   |         help: introduce a variable instead: `b_var`
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html

From a5b4d458a12218b2bbbcb42887d1fe1468f1986e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Thu, 7 Nov 2024 18:34:40 +0000
Subject: [PATCH 06/16] Point at const when intended binding fall-through
 pattern is a const

```
error[E0004]: non-exhaustive patterns: `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
  --> $DIR/intended-binding-pattern-is-const.rs:2:11
   |
LL |     match 1 {
   |           ^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
LL |         x => {}
   |         - this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `x`
   |
   = note: the matched value is of type `i32`
note: constant `x` defined here
  --> $DIR/intended-binding-pattern-is-const.rs:7:5
   |
LL |     const x: i32 = 4;
   |     ^^^^^^^^^^^^
help: if you meant to introduce a binding, use a different name
   |
LL |         x_var => {}
   |          ++++
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
   |
LL |         x => {}, i32::MIN..=3_i32 | 5_i32..=i32::MAX => todo!()
   |                ++++++++++++++++++++++++++++++++++++++++++++++++
```
---
 .../src/thir/pattern/check_match.rs           | 29 ++++++++++++++++---
 .../intended-binding-pattern-is-const.rs      | 10 +++++++
 .../intended-binding-pattern-is-const.stderr  | 27 +++++++++++++++++
 3 files changed, 62 insertions(+), 4 deletions(-)
 create mode 100644 tests/ui/match/intended-binding-pattern-is-const.rs
 create mode 100644 tests/ui/match/intended-binding-pattern-is-const.stderr

diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index a8830b346ae3c..edd51b521fabf 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1116,13 +1116,13 @@ fn report_non_exhaustive_match<'p, 'tcx>(
             if ty.is_ptr_sized_integral() {
                 if ty.inner() == cx.tcx.types.usize {
                     err.note(format!(
-                        "`{ty}` does not have a fixed maximum value, so half-open ranges are necessary to match \
-                             exhaustively",
+                        "`{ty}` does not have a fixed maximum value, so half-open ranges are \
+                         necessary to match exhaustively",
                     ));
                 } else if ty.inner() == cx.tcx.types.isize {
                     err.note(format!(
-                        "`{ty}` does not have fixed minimum and maximum values, so half-open ranges are necessary to match \
-                             exhaustively",
+                        "`{ty}` does not have fixed minimum and maximum values, so half-open \
+                         ranges are necessary to match exhaustively",
                     ));
                 }
             } else if ty.inner() == cx.tcx.types.str_ {
@@ -1143,6 +1143,27 @@ fn report_non_exhaustive_match<'p, 'tcx>(
         }
     }
 
+    for &arm in arms {
+        let arm = &thir.arms[arm];
+        if let PatKind::Constant { opt_def: Some(def_id), .. } = arm.pattern.kind {
+            let const_name = cx.tcx.item_name(def_id);
+            err.span_label(
+                arm.pattern.span,
+                format!(
+                    "this pattern doesn't introduce a new catch-all binding, but rather pattern \
+                     matches against the value of constant `{const_name}`",
+                ),
+            );
+            err.span_note(cx.tcx.def_span(def_id), format!("constant `{const_name}` defined here"));
+            err.span_suggestion_verbose(
+                arm.pattern.span.shrink_to_hi(),
+                "if you meant to introduce a binding, use a different name",
+                "_var".to_string(),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+
     // Whether we suggest the actual missing patterns or `_`.
     let suggest_the_witnesses = witnesses.len() < 4;
     let suggested_arm = if suggest_the_witnesses {
diff --git a/tests/ui/match/intended-binding-pattern-is-const.rs b/tests/ui/match/intended-binding-pattern-is-const.rs
new file mode 100644
index 0000000000000..95c8119cdb9de
--- /dev/null
+++ b/tests/ui/match/intended-binding-pattern-is-const.rs
@@ -0,0 +1,10 @@
+fn main() {
+    match 1 { //~ ERROR non-exhaustive patterns
+        //~^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
+        //~| the matched value is of type `i32`
+        x => {} //~ this pattern doesn't introduce a new catch-all binding
+        //~^ HELP ensure that all possible cases are being handled
+        //~| HELP if you meant to introduce a binding, use a different name
+    }
+    const x: i32 = 4; //~ NOTE constant `x` defined here
+}
diff --git a/tests/ui/match/intended-binding-pattern-is-const.stderr b/tests/ui/match/intended-binding-pattern-is-const.stderr
new file mode 100644
index 0000000000000..99af1c7a16e00
--- /dev/null
+++ b/tests/ui/match/intended-binding-pattern-is-const.stderr
@@ -0,0 +1,27 @@
+error[E0004]: non-exhaustive patterns: `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
+  --> $DIR/intended-binding-pattern-is-const.rs:2:11
+   |
+LL |     match 1 {
+   |           ^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
+...
+LL |         x => {}
+   |         - this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `x`
+   |
+   = note: the matched value is of type `i32`
+note: constant `x` defined here
+  --> $DIR/intended-binding-pattern-is-const.rs:9:5
+   |
+LL |     const x: i32 = 4;
+   |     ^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         x_var => {}
+   |          ++++
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL |         x => {}, i32::MIN..=3_i32 | 5_i32..=i32::MAX => todo!()
+   |                ++++++++++++++++++++++++++++++++++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0004`.

From f563efec156319d726095a82ea3d0f167c7edac7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Thu, 7 Nov 2024 19:34:23 +0000
Subject: [PATCH 07/16] Unify expanded constants and named constants in
 `PatKind`

---
 compiler/rustc_middle/src/thir.rs             | 22 +++---
 compiler/rustc_middle/src/thir/visit.rs       |  4 +-
 .../src/build/custom/parse/instruction.rs     |  2 +-
 .../src/build/matches/match_pair.rs           | 10 ++-
 .../rustc_mir_build/src/build/matches/mod.rs  |  2 +-
 .../rustc_mir_build/src/check_unsafety.rs     | 10 ++-
 .../src/thir/pattern/check_match.rs           |  8 ++-
 .../src/thir/pattern/const_to_pat.rs          |  7 +-
 .../rustc_mir_build/src/thir/pattern/mod.rs   | 37 +++++++---
 compiler/rustc_mir_build/src/thir/print.rs    |  9 +--
 compiler/rustc_pattern_analysis/src/rustc.rs  |  4 +-
 compiler/rustc_ty_utils/src/consts.rs         |  2 +-
 tests/ui/consts/const-pattern-irrefutable.rs  | 21 +++++-
 .../consts/const-pattern-irrefutable.stderr   | 39 +++++++---
 .../const_in_pattern/incomplete-slice.stderr  | 12 ++++
 .../usefulness/match-arm-statics-2.stderr     | 12 ++++
 .../slice-patterns-exhaustiveness.stderr      | 72 +++++++++++++++++++
 17 files changed, 215 insertions(+), 58 deletions(-)

diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 84f5f3a461141..f37c8486df576 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -645,7 +645,7 @@ impl<'tcx> Pat<'tcx> {
             | Binding { subpattern: Some(subpattern), .. }
             | Deref { subpattern }
             | DerefPattern { subpattern, .. }
-            | InlineConstant { subpattern, .. } => subpattern.walk_(it),
+            | ExpandedConstant { subpattern, .. } => subpattern.walk_(it),
             Leaf { subpatterns } | Variant { subpatterns, .. } => {
                 subpatterns.iter().for_each(|field| field.pattern.walk_(it))
             }
@@ -786,16 +786,18 @@ pub enum PatKind<'tcx> {
     /// * `String`, if `string_deref_patterns` is enabled.
     Constant {
         value: mir::Const<'tcx>,
-        /// The `const` item this constant came from, if any.
-        opt_def: Option<DefId>,
     },
 
-    /// Inline constant found while lowering a pattern.
-    InlineConstant {
-        /// [LocalDefId] of the constant, we need this so that we have a
+    /// Inline or named constant found while lowering a pattern.
+    ExpandedConstant {
+        /// [DefId] of the constant, we need this so that we have a
         /// reference that can be used by unsafety checking to visit nested
-        /// unevaluated constants.
-        def: LocalDefId,
+        /// unevaluated constants. If the `DefId` doesn't correspond to a local
+        /// crate, it points at the `const` item.
+        def_id: DefId,
+        /// If `false`, then `def_id` points at a `const` item, otherwise it
+        /// corresponds to a local inline const.
+        is_inline: bool,
         /// If the inline constant is used in a range pattern, this subpattern
         /// represents the range (if both ends are inline constants, there will
         /// be multiple InlineConstant wrappers).
@@ -1086,8 +1088,8 @@ mod size_asserts {
     static_assert_size!(Block, 48);
     static_assert_size!(Expr<'_>, 64);
     static_assert_size!(ExprKind<'_>, 40);
-    static_assert_size!(Pat<'_>, 72);
-    static_assert_size!(PatKind<'_>, 56);
+    static_assert_size!(Pat<'_>, 64);
+    static_assert_size!(PatKind<'_>, 48);
     static_assert_size!(Stmt<'_>, 48);
     static_assert_size!(StmtKind<'_>, 48);
     // tidy-alphabetical-end
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 92c0add65bab7..81202a6eaad6c 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -246,8 +246,8 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
                 visitor.visit_pat(&subpattern.pattern);
             }
         }
-        Constant { value: _, opt_def: _ } => {}
-        InlineConstant { def: _, subpattern } => visitor.visit_pat(subpattern),
+        Constant { value: _ } => {}
+        ExpandedConstant { def_id: _, is_inline: _, subpattern } => visitor.visit_pat(subpattern),
         Range(_) => {}
         Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
             for subpattern in prefix.iter() {
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index 60624855fea99..07964e304b9ed 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -144,7 +144,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
         let mut targets = Vec::new();
         for arm in rest {
             let arm = &self.thir[*arm];
-            let PatKind::Constant { value, opt_def: _ } = arm.pattern.kind else {
+            let PatKind::Constant { value } = arm.pattern.kind else {
                 return Err(ParseError {
                     span: arm.pattern.span,
                     item_description: format!("{:?}", arm.pattern.kind),
diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
index df3cf53eb1787..6beabb5ccdb37 100644
--- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs
@@ -129,7 +129,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
                 }
             }
 
-            PatKind::Constant { value, opt_def: _ } => TestCase::Constant { value },
+            PatKind::Constant { value } => TestCase::Constant { value },
 
             PatKind::AscribeUserType {
                 ascription: thir::Ascription { ref annotation, variance },
@@ -162,7 +162,11 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
                 TestCase::Irrefutable { ascription: None, binding }
             }
 
-            PatKind::InlineConstant { subpattern: ref pattern, def, .. } => {
+            PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => {
+                subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx));
+                default_irrefutable()
+            }
+            PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => {
                 // Apply a type ascription for the inline constant to the value at `match_pair.place`
                 let ascription = place.map(|source| {
                     let span = pattern.span;
@@ -173,7 +177,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
                     })
                     .args;
                     let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
-                        def.to_def_id(),
+                        def_id,
                         ty::UserArgs { args, user_self_ty: None },
                     ));
                     let annotation = ty::CanonicalUserTypeAnnotation {
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index a62d4e9d87373..9f81e1052d6d2 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -917,7 +917,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 self.visit_primary_bindings(subpattern, subpattern_user_ty, f)
             }
 
-            PatKind::InlineConstant { ref subpattern, .. } => {
+            PatKind::ExpandedConstant { ref subpattern, .. } => {
                 self.visit_primary_bindings(subpattern, pattern_user_ty, f)
             }
 
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 33e194fa2462a..52e5f2950a500 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -332,7 +332,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 PatKind::Wild |
                 // these just wrap other patterns, which we recurse on below.
                 PatKind::Or { .. } |
-                PatKind::InlineConstant { .. } |
+                PatKind::ExpandedConstant { .. } |
                 PatKind::AscribeUserType { .. } |
                 PatKind::Error(_) => {}
             }
@@ -386,8 +386,12 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 visit::walk_pat(self, pat);
                 self.inside_adt = old_inside_adt;
             }
-            PatKind::InlineConstant { def, .. } => {
-                self.visit_inner_body(*def);
+            PatKind::ExpandedConstant { def_id, is_inline, .. } => {
+                if let Some(def) = def_id.as_local()
+                    && *is_inline
+                {
+                    self.visit_inner_body(def);
+                }
                 visit::walk_pat(self, pat);
             }
             _ => {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index edd51b521fabf..1cab055864d5c 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -670,11 +670,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
         let mut interpreted_as_const = None;
         let mut interpreted_as_const_sugg = None;
 
-        if let PatKind::Constant { opt_def: Some(def_id), .. }
+        if let PatKind::ExpandedConstant { def_id, is_inline: false, .. }
         | PatKind::AscribeUserType {
-            subpattern: box Pat { kind: PatKind::Constant { opt_def: Some(def_id), .. }, .. },
+            subpattern:
+                box Pat { kind: PatKind::ExpandedConstant { def_id, is_inline: false, .. }, .. },
             ..
         } = pat.kind
+            && let DefKind::Const = self.tcx.def_kind(def_id)
         {
             let span = self.tcx.def_span(def_id);
             let variable = self.tcx.item_name(def_id).to_string();
@@ -1145,7 +1147,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
 
     for &arm in arms {
         let arm = &thir.arms[arm];
-        if let PatKind::Constant { opt_def: Some(def_id), .. } = arm.pattern.kind {
+        if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = arm.pattern.kind {
             let const_name = cx.tcx.item_name(def_id);
             err.span_label(
                 arm.pattern.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 06b13274efced..82632350af59c 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
@@ -266,7 +266,6 @@ impl<'tcx> ConstToPat<'tcx> {
                 // optimization for now.
                 ty::Str => PatKind::Constant {
                     value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)),
-                    opt_def: None,
                 },
                 // All other references are converted into deref patterns and then recursively
                 // convert the dereferenced constant to a pattern that is the sub-pattern of the
@@ -312,17 +311,13 @@ impl<'tcx> ConstToPat<'tcx> {
                 } else {
                     PatKind::Constant {
                         value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)),
-                        opt_def: None,
                     }
                 }
             }
             ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
                 // The raw pointers we see here have been "vetted" by valtree construction to be
                 // just integers, so we simply allow them.
-                PatKind::Constant {
-                    value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)),
-                    opt_def: None,
-                }
+                PatKind::Constant { value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)) }
             }
             ty::FnPtr(..) => {
                 unreachable!(
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 11d06e5a1cc03..c732eeb40a2c0 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -149,15 +149,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             None => Ok((None, None, None)),
             Some(expr) => {
                 let (kind, ascr, inline_const) = match self.lower_lit(expr) {
-                    PatKind::InlineConstant { subpattern, def } => {
-                        (subpattern.kind, None, Some(def))
+                    PatKind::ExpandedConstant { subpattern, def_id, is_inline: true } => {
+                        (subpattern.kind, None, def_id.as_local())
+                    }
+                    PatKind::ExpandedConstant { subpattern, is_inline: false, .. } => {
+                        (subpattern.kind, None, None)
                     }
                     PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
                         (kind, Some(ascription), None)
                     }
                     kind => (kind, None, None),
                 };
-                let value = if let PatKind::Constant { value, opt_def: _ } = kind {
+                let value = if let PatKind::Constant { value } = kind {
                     value
                 } else {
                     let msg = format!(
@@ -251,7 +254,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             (RangeEnd::Included, Some(Ordering::Less)) => {}
             // `x..=y` where `x == y` and `x` and `y` are finite.
             (RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => {
-                kind = PatKind::Constant { value: lo.as_finite().unwrap(), opt_def: None };
+                kind = PatKind::Constant { value: lo.as_finite().unwrap() };
             }
             // `..=x` where `x == ty::MIN`.
             (RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {}
@@ -288,7 +291,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             };
         }
         for def in [lo_inline, hi_inline].into_iter().flatten() {
-            kind = PatKind::InlineConstant { def, subpattern: Box::new(Pat { span, ty, kind }) };
+            kind = PatKind::ExpandedConstant {
+                def_id: def.to_def_id(),
+                is_inline: true,
+                subpattern: Box::new(Pat { span, ty, kind }),
+            };
         }
         Ok(kind)
     }
@@ -562,10 +569,20 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
         let args = self.typeck_results.node_args(id);
         let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
-        let mut pattern = self.const_to_pat(c, ty, id, span);
-        if let PatKind::Constant { value, opt_def: None } = pattern.kind {
-            pattern.kind = PatKind::Constant { value, opt_def: Some(def_id) };
-        }
+        let subpattern = self.const_to_pat(c, ty, id, span);
+        let pattern = if let hir::QPath::Resolved(None, path) = qpath
+            && path.segments.len() == 1
+        {
+            // We only want to mark constants when referenced as bare names that could have been
+            // new bindings if the `const` didn't exist.
+            Box::new(Pat {
+                span,
+                ty,
+                kind: PatKind::ExpandedConstant { subpattern, def_id, is_inline: false },
+            })
+        } else {
+            subpattern
+        };
 
         if !is_associated_const {
             return pattern;
@@ -640,7 +657,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
         let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args };
         let subpattern = self.const_to_pat(ty::Const::new_unevaluated(self.tcx, ct), ty, id, span);
-        PatKind::InlineConstant { subpattern, def: def_id }
+        PatKind::ExpandedConstant { subpattern, def_id: def_id.to_def_id(), is_inline: true }
     }
 
     /// Converts literals, paths and negation of literals to patterns.
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index 43bca812bbd55..6be0ed5fb3115 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -702,14 +702,15 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
                 self.print_pat(subpattern, depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
             }
-            PatKind::Constant { value, opt_def: _ } => {
+            PatKind::Constant { value } => {
                 print_indented!(self, "Constant {", depth_lvl + 1);
                 print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
             }
-            PatKind::InlineConstant { def, subpattern } => {
-                print_indented!(self, "InlineConstant {", depth_lvl + 1);
-                print_indented!(self, format!("def: {:?}", def), depth_lvl + 2);
+            PatKind::ExpandedConstant { def_id, is_inline, subpattern } => {
+                print_indented!(self, "ExpandedConstant {", depth_lvl + 1);
+                print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2);
+                print_indented!(self, format!("is_inline: {is_inline:?}"), depth_lvl + 2);
                 print_indented!(self, "subpattern:", depth_lvl + 2);
                 self.print_pat(subpattern, depth_lvl + 2);
                 print_indented!(self, "}", depth_lvl + 1);
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index ec671150c40c7..7cc6ba24450aa 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -453,7 +453,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
         let fields: Vec<_>;
         match &pat.kind {
             PatKind::AscribeUserType { subpattern, .. }
-            | PatKind::InlineConstant { subpattern, .. } => return self.lower_pat(subpattern),
+            | PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern),
             PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
             PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
                 ctor = Wildcard;
@@ -536,7 +536,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                     ),
                 }
             }
-            PatKind::Constant { value, opt_def: _ } => {
+            PatKind::Constant { value } => {
                 match ty.kind() {
                     ty::Bool => {
                         ctor = match value.try_eval_bool(cx.tcx, cx.param_env) {
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index 12f169d718cc4..637e239a57010 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -370,7 +370,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
         }
 
         match pat.kind {
-            thir::PatKind::Constant { value, opt_def: _ } => value.has_non_region_param(),
+            thir::PatKind::Constant { value } => value.has_non_region_param(),
             thir::PatKind::Range(box thir::PatRange { lo, hi, .. }) => {
                 lo.has_non_region_param() || hi.has_non_region_param()
             }
diff --git a/tests/ui/consts/const-pattern-irrefutable.rs b/tests/ui/consts/const-pattern-irrefutable.rs
index c590ec8fcd361..759d2e8b2edeb 100644
--- a/tests/ui/consts/const-pattern-irrefutable.rs
+++ b/tests/ui/consts/const-pattern-irrefutable.rs
@@ -1,7 +1,7 @@
 mod foo {
     pub const b: u8 = 2;
     //~^ missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable
-    pub const d: u8 = 2;
+    pub const d: (u8, u8) = (2, 1);
     //~^ missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
 }
 
@@ -11,6 +11,15 @@ use foo::d;
 const a: u8 = 2;
 //~^ missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
 
+#[derive(PartialEq)]
+struct S {
+    foo: u8,
+}
+
+const e: S = S {
+    foo: 0,
+};
+
 fn main() {
     let a = 4;
     //~^ ERROR refutable pattern in local binding
@@ -20,9 +29,15 @@ fn main() {
     //~^ ERROR refutable pattern in local binding
     //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
     //~| HELP introduce a variable instead
-    let d = 4;
+    let d = (4, 4);
     //~^ ERROR refutable pattern in local binding
-    //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
+    //~| patterns `(0_u8..=1_u8, _)` and `(3_u8..=u8::MAX, _)` not covered
+    //~| HELP introduce a variable instead
+    let e = S {
+    //~^ ERROR refutable pattern in local binding
+    //~| pattern `S { foo: 1_u8..=u8::MAX }` not covered
     //~| HELP introduce a variable instead
+        foo: 1,
+    };
     fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115).
 }
diff --git a/tests/ui/consts/const-pattern-irrefutable.stderr b/tests/ui/consts/const-pattern-irrefutable.stderr
index c118ce9e48f2f..4206e3fe704da 100644
--- a/tests/ui/consts/const-pattern-irrefutable.stderr
+++ b/tests/ui/consts/const-pattern-irrefutable.stderr
@@ -1,5 +1,5 @@
 error[E0005]: refutable pattern in local binding
-  --> $DIR/const-pattern-irrefutable.rs:15:9
+  --> $DIR/const-pattern-irrefutable.rs:24:9
    |
 LL | const a: u8 = 2;
    | ----------- missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
@@ -15,7 +15,7 @@ LL |     let a = 4;
    = note: the matched value is of type `u8`
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/const-pattern-irrefutable.rs:19:9
+  --> $DIR/const-pattern-irrefutable.rs:28:9
    |
 LL |     pub const b: u8 = 2;
    |     --------------- missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable
@@ -31,21 +31,42 @@ LL |     let c = 4;
    = note: the matched value is of type `u8`
 
 error[E0005]: refutable pattern in local binding
-  --> $DIR/const-pattern-irrefutable.rs:23:9
+  --> $DIR/const-pattern-irrefutable.rs:32:9
    |
-LL |     pub const d: u8 = 2;
-   |     --------------- missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
+LL |     pub const d: (u8, u8) = (2, 1);
+   |     --------------------- missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
 ...
-LL |     let d = 4;
+LL |     let d = (4, 4);
    |         ^
    |         |
-   |         patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
+   |         patterns `(0_u8..=1_u8, _)` and `(3_u8..=u8::MAX, _)` not covered
    |         help: introduce a variable instead: `d_var`
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-   = note: the matched value is of type `u8`
+   = note: the matched value is of type `(u8, u8)`
+
+error[E0005]: refutable pattern in local binding
+  --> $DIR/const-pattern-irrefutable.rs:36:9
+   |
+LL | const e: S = S {
+   | ---------- missing patterns are not covered because `e` is interpreted as a constant pattern, not a new variable
+...
+LL |     let e = S {
+   |         ^
+   |         |
+   |         pattern `S { foo: 1_u8..=u8::MAX }` not covered
+   |         help: introduce a variable instead: `e_var`
+   |
+   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+note: `S` defined here
+  --> $DIR/const-pattern-irrefutable.rs:15:8
+   |
+LL | struct S {
+   |        ^
+   = note: the matched value is of type `S`
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0005`.
diff --git a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr
index bd61f43727be9..c73d1f059007c 100644
--- a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr
+++ b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr
@@ -3,8 +3,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
    |
 LL |     match &[][..] {
    |           ^^^^^^^ patterns `&[]` and `&[_, _, ..]` not covered
+LL |
+LL |         E_SL => {}
+   |         ---- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `E_SL`
    |
    = note: the matched value is of type `&[E]`
+note: constant `E_SL` defined here
+  --> $DIR/incomplete-slice.rs:6:1
+   |
+LL | const E_SL: &[E] = &[E::A];
+   | ^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         E_SL_var => {}
+   |             ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         E_SL => {},
diff --git a/tests/ui/pattern/usefulness/match-arm-statics-2.stderr b/tests/ui/pattern/usefulness/match-arm-statics-2.stderr
index e4dd35a59958e..60b4fcca28613 100644
--- a/tests/ui/pattern/usefulness/match-arm-statics-2.stderr
+++ b/tests/ui/pattern/usefulness/match-arm-statics-2.stderr
@@ -3,8 +3,20 @@ error[E0004]: non-exhaustive patterns: `(true, false)` not covered
    |
 LL |     match (true, false) {
    |           ^^^^^^^^^^^^^ pattern `(true, false)` not covered
+LL |
+LL |         TRUE_TRUE => (),
+   |         --------- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `TRUE_TRUE`
    |
    = note: the matched value is of type `(bool, bool)`
+note: constant `TRUE_TRUE` defined here
+  --> $DIR/match-arm-statics-2.rs:14:1
+   |
+LL | const TRUE_TRUE: (bool, bool) = (true, true);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         TRUE_TRUE_var => (),
+   |                  ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         (false, true) => (),
diff --git a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
index a8786d02414c8..0a3991fe3d160 100644
--- a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
+++ b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr
@@ -199,8 +199,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
    |
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
+LL |
+LL |         CONST => {}
+   |         ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
    |
    = note: the matched value is of type `&[bool]`
+note: constant `CONST` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:88:5
+   |
+LL |     const CONST: &[bool] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST_var => {}
+   |              ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         CONST => {},
@@ -212,8 +224,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
    |
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
+LL |
+LL |         CONST => {}
+   |         ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
    |
    = note: the matched value is of type `&[bool]`
+note: constant `CONST` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:88:5
+   |
+LL |     const CONST: &[bool] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST_var => {}
+   |              ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         &[false] => {},
@@ -225,8 +249,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
    |
 LL |     match s {
    |           ^ patterns `&[]` and `&[_, _, ..]` not covered
+...
+LL |         CONST => {}
+   |         ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
    |
    = note: the matched value is of type `&[bool]`
+note: constant `CONST` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:88:5
+   |
+LL |     const CONST: &[bool] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST_var => {}
+   |              ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         CONST => {},
@@ -238,8 +274,20 @@ error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
    |
 LL |     match s {
    |           ^ pattern `&[_, _, ..]` not covered
+...
+LL |         CONST => {}
+   |         ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
    |
    = note: the matched value is of type `&[bool]`
+note: constant `CONST` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:88:5
+   |
+LL |     const CONST: &[bool] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST_var => {}
+   |              ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         CONST => {},
@@ -251,8 +299,20 @@ error[E0004]: non-exhaustive patterns: `&[false]` not covered
    |
 LL |     match s {
    |           ^ pattern `&[false]` not covered
+...
+LL |         CONST => {}
+   |         ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST`
    |
    = note: the matched value is of type `&[bool]`
+note: constant `CONST` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:88:5
+   |
+LL |     const CONST: &[bool] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST_var => {}
+   |              ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         &[_, _, ..] => {},
@@ -264,8 +324,20 @@ error[E0004]: non-exhaustive patterns: `&[false]` not covered
    |
 LL |     match s1 {
    |           ^^ pattern `&[false]` not covered
+LL |
+LL |         CONST1 => {}
+   |         ------ this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST1`
    |
    = note: the matched value is of type `&[bool; 1]`
+note: constant `CONST1` defined here
+  --> $DIR/slice-patterns-exhaustiveness.rs:124:5
+   |
+LL |     const CONST1: &[bool; 1] = &[true];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+help: if you meant to introduce a binding, use a different name
+   |
+LL |         CONST1_var => {}
+   |               ++++
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
 LL ~         CONST1 => {},

From f1772d57399272f69fa69ad10ae21d380efc2e7e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Thu, 7 Nov 2024 19:40:27 +0000
Subject: [PATCH 08/16] Make suggestion verbose

---
 compiler/rustc_mir_build/src/errors.rs        |  3 +-
 .../2229_closure_analysis/bad-pattern.stderr  |  9 ++---
 .../consts/const-pattern-irrefutable.stderr   | 36 ++++++++++---------
 tests/ui/mir/issue-112269.stderr              | 18 +++++-----
 ...const-pat-non-exaustive-let-new-var.stderr |  9 ++---
 5 files changed, 42 insertions(+), 33 deletions(-)

diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 04eb7ffe77650..4443d9aebc60d 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -913,7 +913,8 @@ impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> {
 #[suggestion(
     mir_build_interpreted_as_const,
     code = "{variable}_var",
-    applicability = "maybe-incorrect"
+    applicability = "maybe-incorrect",
+    style = "verbose"
 )]
 pub(crate) struct InterpretedAsConst {
     #[primary_span]
diff --git a/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr b/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr
index 5692d530b0698..5f980c46a1f54 100644
--- a/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr
+++ b/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr
@@ -101,14 +101,15 @@ LL |     const PAT: u32 = 0;
    |     -------------- missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable
 ...
 LL |         let PAT = v1;
-   |             ^^^
-   |             |
-   |             pattern `1_u32..=u32::MAX` not covered
-   |             help: introduce a variable instead: `PAT_var`
+   |             ^^^ pattern `1_u32..=u32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `u32`
+help: introduce a variable instead
+   |
+LL |         let PAT_var = v1;
+   |             ~~~~~~~
 
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/consts/const-pattern-irrefutable.stderr b/tests/ui/consts/const-pattern-irrefutable.stderr
index 4206e3fe704da..afb67a3a118a4 100644
--- a/tests/ui/consts/const-pattern-irrefutable.stderr
+++ b/tests/ui/consts/const-pattern-irrefutable.stderr
@@ -5,14 +5,15 @@ LL | const a: u8 = 2;
    | ----------- missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
 ...
 LL |     let a = 4;
-   |         ^
-   |         |
-   |         patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-   |         help: introduce a variable instead: `a_var`
+   |         ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `u8`
+help: introduce a variable instead
+   |
+LL |     let a_var = 4;
+   |         ~~~~~
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/const-pattern-irrefutable.rs:28:9
@@ -21,14 +22,15 @@ LL |     pub const b: u8 = 2;
    |     --------------- missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable
 ...
 LL |     let c = 4;
-   |         ^
-   |         |
-   |         patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-   |         help: introduce a variable instead: `b_var`
+   |         ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `u8`
+help: introduce a variable instead
+   |
+LL |     let b_var = 4;
+   |         ~~~~~
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/const-pattern-irrefutable.rs:32:9
@@ -37,14 +39,15 @@ LL |     pub const d: (u8, u8) = (2, 1);
    |     --------------------- missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
 ...
 LL |     let d = (4, 4);
-   |         ^
-   |         |
-   |         patterns `(0_u8..=1_u8, _)` and `(3_u8..=u8::MAX, _)` not covered
-   |         help: introduce a variable instead: `d_var`
+   |         ^ patterns `(0_u8..=1_u8, _)` and `(3_u8..=u8::MAX, _)` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `(u8, u8)`
+help: introduce a variable instead
+   |
+LL |     let d_var = (4, 4);
+   |         ~~~~~
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/const-pattern-irrefutable.rs:36:9
@@ -53,10 +56,7 @@ LL | const e: S = S {
    | ---------- missing patterns are not covered because `e` is interpreted as a constant pattern, not a new variable
 ...
 LL |     let e = S {
-   |         ^
-   |         |
-   |         pattern `S { foo: 1_u8..=u8::MAX }` not covered
-   |         help: introduce a variable instead: `e_var`
+   |         ^ pattern `S { foo: 1_u8..=u8::MAX }` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
@@ -66,6 +66,10 @@ note: `S` defined here
 LL | struct S {
    |        ^
    = note: the matched value is of type `S`
+help: introduce a variable instead
+   |
+LL |     let e_var = S {
+   |         ~~~~~
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/mir/issue-112269.stderr b/tests/ui/mir/issue-112269.stderr
index 945a7e25dd0e3..adb662c98a7e8 100644
--- a/tests/ui/mir/issue-112269.stderr
+++ b/tests/ui/mir/issue-112269.stderr
@@ -4,14 +4,15 @@ error[E0005]: refutable pattern in local binding
 LL |     const x: i32 = 4;
    |     ------------ missing patterns are not covered because `x` is interpreted as a constant pattern, not a new variable
 LL |     let x: i32 = 3;
-   |         ^
-   |         |
-   |         patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
-   |         help: introduce a variable instead: `x_var`
+   |         ^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
+help: introduce a variable instead
+   |
+LL |     let x_var: i32 = 3;
+   |         ~~~~~
 
 error[E0005]: refutable pattern in local binding
   --> $DIR/issue-112269.rs:7:9
@@ -19,14 +20,15 @@ error[E0005]: refutable pattern in local binding
 LL |     const y: i32 = 3;
    |     ------------ missing patterns are not covered because `y` is interpreted as a constant pattern, not a new variable
 LL |     let y = 4;
-   |         ^
-   |         |
-   |         patterns `i32::MIN..=2_i32` and `4_i32..=i32::MAX` not covered
-   |         help: introduce a variable instead: `y_var`
+   |         ^ patterns `i32::MIN..=2_i32` and `4_i32..=i32::MAX` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
+help: introduce a variable instead
+   |
+LL |     let y_var = 4;
+   |         ~~~~~
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
index 29c4b2905ebd9..a275d8e4e8397 100644
--- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
+++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
@@ -2,10 +2,7 @@ error[E0005]: refutable pattern in local binding
   --> $DIR/const-pat-non-exaustive-let-new-var.rs:2:9
    |
 LL |     let A = 3;
-   |         ^
-   |         |
-   |         patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
-   |         help: introduce a variable instead: `A_var`
+   |         ^ patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
 ...
 LL |     const A: i32 = 2;
    |     ------------ missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable
@@ -13,6 +10,10 @@ LL |     const A: i32 = 2;
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `i32`
+help: introduce a variable instead
+   |
+LL |     let A_var = 3;
+   |         ~~~~~
 
 error: aborting due to 1 previous error
 

From bb37e5d3cd4aace7141f5dfce401f6532cdb4d87 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Tue, 12 Nov 2024 00:59:11 +0000
Subject: [PATCH 09/16] review comments

---
 compiler/rustc_middle/src/thir.rs                        | 7 +++++--
 compiler/rustc_mir_build/src/thir/pattern/check_match.rs | 4 ----
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index f37c8486df576..d50d2e19f2da7 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -789,11 +789,14 @@ pub enum PatKind<'tcx> {
     },
 
     /// Inline or named constant found while lowering a pattern.
+    ///
+    /// We only mark patterns referencing constants when they are bare names that could have been
+    /// new bindings if the `const` didn't exist.
     ExpandedConstant {
         /// [DefId] of the constant, we need this so that we have a
         /// reference that can be used by unsafety checking to visit nested
-        /// unevaluated constants. If the `DefId` doesn't correspond to a local
-        /// crate, it points at the `const` item.
+        /// unevaluated constants and for diagnostics. If the `DefId` doesn't
+        /// correspond to a local crate, it points at the `const` item.
         def_id: DefId,
         /// If `false`, then `def_id` points at a `const` item, otherwise it
         /// corresponds to a local inline const.
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 1cab055864d5c..db0f8a28293cd 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -696,10 +696,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
                 misc_suggestion = Some(MiscPatternSuggestion::AttemptedIntegerLiteral {
                     start_span: pat.span.shrink_to_lo(),
                 });
-            } else if snippet.chars().all(|c| c.is_alphanumeric() || c == '_') {
-                interpreted_as_const = Some(pat.span);
-                interpreted_as_const_sugg =
-                    Some(InterpretedAsConst { span: pat.span, variable: snippet });
             }
         }
 

From 6480b76e458c14a87ea3c41f1eb96aa141044565 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Wed, 13 Nov 2024 21:54:46 +0000
Subject: [PATCH 10/16] review comments

- Remove check for "how many path segments is the pattern"
- Check before suggesting if the path has multiple path segments
---
 .../src/thir/pattern/check_match.rs           |  9 ++++-
 .../rustc_mir_build/src/thir/pattern/mod.rs   | 38 +++++++++----------
 2 files changed, 26 insertions(+), 21 deletions(-)

diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index db0f8a28293cd..4b872d9b7f77f 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -677,6 +677,9 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             ..
         } = pat.kind
             && let DefKind::Const = self.tcx.def_kind(def_id)
+            && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
+            // We filter out paths with multiple path::segments.
+            && snippet.chars().all(|c| c.is_alphanumeric() || c == '_')
         {
             let span = self.tcx.def_span(def_id);
             let variable = self.tcx.item_name(def_id).to_string();
@@ -1143,7 +1146,11 @@ fn report_non_exhaustive_match<'p, 'tcx>(
 
     for &arm in arms {
         let arm = &thir.arms[arm];
-        if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = arm.pattern.kind {
+        if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = arm.pattern.kind
+            && let Ok(snippet) = cx.tcx.sess.source_map().span_to_snippet(arm.pattern.span)
+            // We filter out paths with multiple path::segments.
+            && snippet.chars().all(|c| c.is_alphanumeric() || c == '_')
+        {
             let const_name = cx.tcx.item_name(def_id);
             err.span_label(
                 arm.pattern.span,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index c732eeb40a2c0..9b63d78819431 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -160,13 +160,19 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     }
                     kind => (kind, None, None),
                 };
-                let value = if let PatKind::Constant { value } = kind {
-                    value
-                } else {
-                    let msg = format!(
-                        "found bad range pattern endpoint `{expr:?}` outside of error recovery"
-                    );
-                    return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
+                let value = match kind {
+                    PatKind::Constant { value } => value,
+                    PatKind::ExpandedConstant { subpattern, .. }
+                        if let PatKind::Constant { value } = subpattern.kind =>
+                    {
+                        value
+                    }
+                    _ => {
+                        let msg = format!(
+                            "found bad range pattern endpoint `{expr:?}` outside of error recovery"
+                        );
+                        return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
+                    }
                 };
                 Ok((Some(PatRangeBoundary::Finite(value)), ascr, inline_const))
             }
@@ -570,19 +576,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         let args = self.typeck_results.node_args(id);
         let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
         let subpattern = self.const_to_pat(c, ty, id, span);
-        let pattern = if let hir::QPath::Resolved(None, path) = qpath
-            && path.segments.len() == 1
-        {
-            // We only want to mark constants when referenced as bare names that could have been
-            // new bindings if the `const` didn't exist.
-            Box::new(Pat {
-                span,
-                ty,
-                kind: PatKind::ExpandedConstant { subpattern, def_id, is_inline: false },
-            })
-        } else {
-            subpattern
-        };
+        let pattern = Box::new(Pat {
+            span,
+            ty,
+            kind: PatKind::ExpandedConstant { subpattern, def_id, is_inline: false },
+        });
 
         if !is_associated_const {
             return pattern;

From 912ee65ccdad256c855a2ae67925ca7efd2eee99 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Sun, 17 Nov 2024 23:39:51 +0000
Subject: [PATCH 11/16] review comment: modify doc comment

---
 compiler/rustc_middle/src/thir.rs | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index d50d2e19f2da7..70df237901616 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -788,10 +788,8 @@ pub enum PatKind<'tcx> {
         value: mir::Const<'tcx>,
     },
 
-    /// Inline or named constant found while lowering a pattern.
-    ///
-    /// We only mark patterns referencing constants when they are bare names that could have been
-    /// new bindings if the `const` didn't exist.
+    /// Pattern obtained by converting a constant (inline or named) to its pattern
+    /// representation using `const_to_pat`.
     ExpandedConstant {
         /// [DefId] of the constant, we need this so that we have a
         /// reference that can be used by unsafety checking to visit nested

From 29acf8b422ab446fa4cd51fbb0e5a145f30c1cfc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Sun, 17 Nov 2024 23:58:22 +0000
Subject: [PATCH 12/16] Account for `ExpandedConstant` in `parse_match`

---
 .../src/build/custom/parse/instruction.rs     | 20 +++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index 07964e304b9ed..62d173987fce2 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -144,12 +144,20 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
         let mut targets = Vec::new();
         for arm in rest {
             let arm = &self.thir[*arm];
-            let PatKind::Constant { value } = arm.pattern.kind else {
-                return Err(ParseError {
-                    span: arm.pattern.span,
-                    item_description: format!("{:?}", arm.pattern.kind),
-                    expected: "constant pattern".to_string(),
-                });
+            let value = match arm.pattern.kind {
+                PatKind::Constant { value } => value,
+                PatKind::ExpandedConstant { ref subpattern, def_id: _, is_inline: false }
+                    if let PatKind::Constant { value } = subpattern.kind =>
+                {
+                    value
+                }
+                _ => {
+                    return Err(ParseError {
+                        span: arm.pattern.span,
+                        item_description: format!("{:?}", arm.pattern.kind),
+                        expected: "constant pattern".to_string(),
+                    });
+                }
             };
             values.push(value.eval_bits(self.tcx, self.param_env));
             targets.push(self.parse_block(arm.body)?);

From f37d021d6ccb7949ba8e8b2a5d6e91686063da2a Mon Sep 17 00:00:00 2001
From: daxpedda <daxpedda@gmail.com>
Date: Wed, 20 Nov 2024 13:48:48 +0100
Subject: [PATCH 13/16] Account for `wasm32v1-none` when exporting TLS symbols

---
 compiler/rustc_codegen_ssa/src/back/linker.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 4f3664a503d61..6ee599c9964c5 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -1279,7 +1279,7 @@ impl<'a> WasmLd<'a> {
         let mut wasm_ld = WasmLd { cmd, sess };
         if sess.target_features.contains(&sym::atomics) {
             wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]);
-            if sess.target.os == "unknown" {
+            if sess.target.os == "unknown" || sess.target.os == "none" {
                 wasm_ld.link_args(&[
                     "--export=__wasm_init_tls",
                     "--export=__tls_size",
@@ -1403,7 +1403,7 @@ impl<'a> Linker for WasmLd<'a> {
         // symbols explicitly passed via the `--export` flags above and hides all
         // others. Various bits and pieces of wasm32-unknown-unknown tooling use
         // this, so be sure these symbols make their way out of the linker as well.
-        if self.sess.target.os == "unknown" {
+        if self.sess.target.os == "unknown" || self.sess.target.os == "none" {
             self.link_args(&["--export=__heap_base", "--export=__data_end"]);
         }
     }

From 06e66d78c3a104b30fd59714d4dbb1a5d9f351bb Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Tue, 19 Nov 2024 21:23:10 +0000
Subject: [PATCH 14/16] Rip out built-in PointerLike impl

---
 compiler/rustc_middle/src/ty/context.rs       | 14 ---------
 .../src/solve/assembly/mod.rs                 | 10 ------
 .../src/solve/effect_goals.rs                 |  7 -----
 .../src/solve/normalizes_to/mod.rs            |  7 -----
 .../src/solve/trait_goals.rs                  | 26 ----------------
 .../src/traits/select/candidate_assembly.rs   | 31 -------------------
 compiler/rustc_type_ir/src/interner.rs        |  9 +-----
 compiler/rustc_type_ir/src/lang_items.rs      |  1 -
 8 files changed, 1 insertion(+), 104 deletions(-)

diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index ad42eacf82318..b4d29f08a0fc7 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -602,19 +602,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.coroutine_is_async_gen(coroutine_def_id)
     }
 
-    // We don't use `TypingEnv` here as it's only defined in `rustc_middle` and
-    // `rustc_next_trait_solver` shouldn't have to know about it.
-    fn layout_is_pointer_like(
-        self,
-        typing_mode: ty::TypingMode<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> bool {
-        let typing_env = ty::TypingEnv { typing_mode, param_env };
-        self.layout_of(self.erase_regions(typing_env).as_query_input(self.erase_regions(ty)))
-            .is_ok_and(|layout| layout.layout.is_pointer_like(&self.data_layout))
-    }
-
     type UnsizingParams = &'tcx rustc_index::bit_set::BitSet<u32>;
     fn unsizing_params_for_adt(self, adt_def_id: DefId) -> Self::UnsizingParams {
         self.unsizing_params_for_adt(adt_def_id)
@@ -688,7 +675,6 @@ bidirectional_lang_item_map! {
     Metadata,
     Option,
     PointeeTrait,
-    PointerLike,
     Poll,
     Sized,
     TransmuteTrait,
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index ebf7372926f8a..78344571088f5 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -159,13 +159,6 @@ where
         goal: Goal<I, Self>,
     ) -> Result<Candidate<I>, NoSolution>;
 
-    /// A type is `PointerLike` if we can compute its layout, and that layout
-    /// matches the layout of `usize`.
-    fn consider_builtin_pointer_like_candidate(
-        ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution>;
-
     /// A type is a `FnPtr` if it is of `FnPtr` type.
     fn consider_builtin_fn_ptr_trait_candidate(
         ecx: &mut EvalCtxt<'_, D>,
@@ -449,9 +442,6 @@ where
                         ty::ClosureKind::FnOnce,
                     )
                 }
-                Some(TraitSolverLangItem::PointerLike) => {
-                    G::consider_builtin_pointer_like_candidate(self, goal)
-                }
                 Some(TraitSolverLangItem::FnPtrTrait) => {
                     G::consider_builtin_fn_ptr_trait_candidate(self, goal)
                 }
diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
index 282ca2fedbc4d..1f5ca71dd6f59 100644
--- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
@@ -210,13 +210,6 @@ where
         Err(NoSolution)
     }
 
-    fn consider_builtin_pointer_like_candidate(
-        _ecx: &mut EvalCtxt<'_, D>,
-        _goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution> {
-        unreachable!("PointerLike is not const")
-    }
-
     fn consider_builtin_fn_ptr_trait_candidate(
         _ecx: &mut EvalCtxt<'_, D>,
         _goal: Goal<I, Self>,
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index 8a01659953d41..6b407640426b7 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -363,13 +363,6 @@ where
         panic!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
     }
 
-    fn consider_builtin_pointer_like_candidate(
-        _ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution> {
-        panic!("`PointerLike` does not have an associated type: {:?}", goal);
-    }
-
     fn consider_builtin_fn_ptr_trait_candidate(
         _ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index e64d4eed9d862..ce16258d1806c 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -248,32 +248,6 @@ where
         )
     }
 
-    fn consider_builtin_pointer_like_candidate(
-        ecx: &mut EvalCtxt<'_, D>,
-        goal: Goal<I, Self>,
-    ) -> Result<Candidate<I>, NoSolution> {
-        if goal.predicate.polarity != ty::PredicatePolarity::Positive {
-            return Err(NoSolution);
-        }
-
-        let cx = ecx.cx();
-        // But if there are inference variables, we have to wait until it's resolved.
-        if (goal.param_env, goal.predicate.self_ty()).has_non_region_infer() {
-            return ecx.forced_ambiguity(MaybeCause::Ambiguity);
-        }
-
-        if cx.layout_is_pointer_like(
-            ecx.typing_mode(goal.param_env),
-            goal.param_env,
-            goal.predicate.self_ty(),
-        ) {
-            ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
-                .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
-        } else {
-            Err(NoSolution)
-        }
-    }
-
     fn consider_builtin_fn_ptr_trait_candidate(
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 1e0c487c4d492..345e1cc31f32b 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -111,8 +111,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 self.assemble_candidates_for_transmutability(obligation, &mut candidates);
             } else if tcx.is_lang_item(def_id, LangItem::Tuple) {
                 self.assemble_candidate_for_tuple(obligation, &mut candidates);
-            } else if tcx.is_lang_item(def_id, LangItem::PointerLike) {
-                self.assemble_candidate_for_pointer_like(obligation, &mut candidates);
             } else if tcx.is_lang_item(def_id, LangItem::FnPtrTrait) {
                 self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates);
             } else {
@@ -1216,35 +1214,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
     }
 
-    fn assemble_candidate_for_pointer_like(
-        &mut self,
-        obligation: &PolyTraitObligation<'tcx>,
-        candidates: &mut SelectionCandidateSet<'tcx>,
-    ) {
-        // The regions of a type don't affect the size of the type
-        let tcx = self.tcx();
-        let self_ty = tcx.instantiate_bound_regions_with_erased(obligation.predicate.self_ty());
-
-        // But if there are inference variables, we have to wait until it's resolved.
-        if (obligation.param_env, self_ty).has_non_region_infer() {
-            candidates.ambiguous = true;
-            return;
-        }
-
-        // We should erase regions from both the param-env and type, since both
-        // may have infer regions. Specifically, after canonicalizing and instantiating,
-        // early bound regions turn into region vars in both the new and old solver.
-        let key = self.infcx.pseudo_canonicalize_query(
-            tcx.erase_regions(obligation.param_env),
-            tcx.erase_regions(self_ty),
-        );
-        if let Ok(layout) = tcx.layout_of(key)
-            && layout.layout.is_pointer_like(&tcx.data_layout)
-        {
-            candidates.vec.push(BuiltinCandidate { has_nested: false });
-        }
-    }
-
     fn assemble_candidates_for_fn_ptr_trait(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 6e6cf91d85524..4e1715dbd0fc6 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -13,7 +13,7 @@ use crate::lang_items::TraitSolverLangItem;
 use crate::relate::Relate;
 use crate::solve::{CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult};
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
-use crate::{self as ty, TypingMode, search_graph};
+use crate::{self as ty, search_graph};
 
 pub trait Interner:
     Sized
@@ -278,13 +278,6 @@ pub trait Interner:
     fn coroutine_is_gen(self, coroutine_def_id: Self::DefId) -> bool;
     fn coroutine_is_async_gen(self, coroutine_def_id: Self::DefId) -> bool;
 
-    fn layout_is_pointer_like(
-        self,
-        typing_mode: TypingMode<Self>,
-        param_env: Self::ParamEnv,
-        ty: Self::Ty,
-    ) -> bool;
-
     type UnsizingParams: Deref<Target = BitSet<u32>>;
     fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams;
 
diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs
index d6ca22a90a4db..df43346065d40 100644
--- a/compiler/rustc_type_ir/src/lang_items.rs
+++ b/compiler/rustc_type_ir/src/lang_items.rs
@@ -31,7 +31,6 @@ pub enum TraitSolverLangItem {
     Metadata,
     Option,
     PointeeTrait,
-    PointerLike,
     Poll,
     Sized,
     TransmuteTrait,

From 228068bc6efb16f359b5318e66fa789c2f58ce60 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Wed, 20 Nov 2024 02:46:56 +0000
Subject: [PATCH 15/16] Make PointerLike opt-in as a trait

---
 .../src/coherence/builtin.rs                  | 85 ++++++++++++++++---
 library/alloc/src/boxed.rs                    |  6 ++
 library/alloc/src/lib.rs                      |  1 +
 library/core/src/marker.rs                    | 12 +++
 tests/crashes/113280.rs                       | 16 ----
 tests/crashes/127676.rs                       |  8 --
 tests/ui/dyn-star/async-block-dyn-star.rs     |  9 ++
 tests/ui/dyn-star/async-block-dyn-star.stderr | 20 +++++
 ...ize-at-cast-polymorphic-bad.current.stderr | 11 ++-
 ...k-size-at-cast-polymorphic-bad.next.stderr | 11 ++-
 tests/ui/dyn-star/drop.rs                     |  7 +-
 tests/ui/dyn-star/enum-cast.rs                |  7 +-
 tests/ui/dyn-star/error.rs                    |  2 +-
 tests/ui/dyn-star/error.stderr                |  4 +-
 tests/ui/dyn-star/float-as-dyn-star.rs        | 16 ++++
 tests/ui/dyn-star/float-as-dyn-star.stderr    | 21 +++++
 tests/ui/dyn-star/upcast.stderr               | 10 ++-
 17 files changed, 194 insertions(+), 52 deletions(-)
 delete mode 100644 tests/crashes/113280.rs
 delete mode 100644 tests/crashes/127676.rs
 create mode 100644 tests/ui/dyn-star/async-block-dyn-star.rs
 create mode 100644 tests/ui/dyn-star/async-block-dyn-star.stderr
 create mode 100644 tests/ui/dyn-star/float-as-dyn-star.rs
 create mode 100644 tests/ui/dyn-star/float-as-dyn-star.stderr

diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index c2ad61820a7f2..3b49bc41ffe43 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -37,22 +37,19 @@ pub(super) fn check_trait<'tcx>(
 ) -> Result<(), ErrorGuaranteed> {
     let lang_items = tcx.lang_items();
     let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header };
-    let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop);
-    res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy));
-    res = res.and(checker.check(lang_items.const_param_ty_trait(), |checker| {
+    checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?;
+    checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?;
+    checker.check(lang_items.const_param_ty_trait(), |checker| {
         visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy)
-    }));
-    res = res.and(checker.check(lang_items.unsized_const_param_ty_trait(), |checker| {
+    })?;
+    checker.check(lang_items.unsized_const_param_ty_trait(), |checker| {
         visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy)
-    }));
-
-    res = res.and(
-        checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized),
-    );
-    res.and(
-        checker
-            .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn),
-    )
+    })?;
+    checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?;
+    checker
+        .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?;
+    checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?;
+    Ok(())
 }
 
 struct Checker<'tcx> {
@@ -663,3 +660,63 @@ fn infringing_fields_error<'tcx>(
 
     err.emit()
 }
+
+fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
+    let tcx = checker.tcx;
+    let typing_env = ty::TypingEnv::non_body_analysis(tcx, checker.impl_def_id);
+    let impl_span = tcx.def_span(checker.impl_def_id);
+    let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
+
+    // If an ADT is repr(transparent)...
+    if let ty::Adt(def, args) = *self_ty.kind()
+        && def.repr().transparent()
+    {
+        // FIXME(compiler-errors): This should and could be deduplicated into a query.
+        // Find the nontrivial field.
+        let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, def.did());
+        let nontrivial_field = def.all_fields().find(|field_def| {
+            let field_ty = tcx.type_of(field_def.did).instantiate_identity();
+            !tcx.layout_of(adt_typing_env.as_query_input(field_ty))
+                .is_ok_and(|layout| layout.layout.is_1zst())
+        });
+
+        if let Some(nontrivial_field) = nontrivial_field {
+            // Check that the nontrivial field implements `PointerLike`.
+            let nontrivial_field = nontrivial_field.ty(tcx, args);
+            let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
+            let ocx = ObligationCtxt::new(&infcx);
+            ocx.register_bound(
+                ObligationCause::misc(impl_span, checker.impl_def_id),
+                param_env,
+                nontrivial_field,
+                tcx.lang_items().pointer_like().unwrap(),
+            );
+            // FIXME(dyn-star): We should regionck this implementation.
+            if ocx.select_all_or_error().is_empty() {
+                return Ok(());
+            }
+        }
+    }
+
+    let is_permitted_primitive = match *self_ty.kind() {
+        ty::Adt(def, _) => def.is_box(),
+        ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
+        _ => false,
+    };
+
+    if is_permitted_primitive
+        && let Ok(layout) = tcx.layout_of(typing_env.as_query_input(self_ty))
+        && layout.layout.is_pointer_like(&tcx.data_layout)
+    {
+        return Ok(());
+    }
+
+    Err(tcx
+        .dcx()
+        .struct_span_err(
+            impl_span,
+            "implementation must be applied to type that has the same ABI as a pointer, \
+            or is `repr(transparent)` and whose field is `PointerLike`",
+        )
+        .emit())
+}
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index ac3e4626ee5eb..ee60ec0fbacbe 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -191,6 +191,8 @@ use core::error::{self, Error};
 use core::fmt;
 use core::future::Future;
 use core::hash::{Hash, Hasher};
+#[cfg(not(bootstrap))]
+use core::marker::PointerLike;
 use core::marker::{Tuple, Unsize};
 use core::mem::{self, SizedTypeProperties};
 use core::ops::{
@@ -2131,3 +2133,7 @@ impl<E: Error> Error for Box<E> {
         Error::provide(&**self, request);
     }
 }
+
+#[cfg(not(bootstrap))]
+#[unstable(feature = "pointer_like_trait", issue = "none")]
+impl<T> PointerLike for Box<T> {}
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 7839fe04b8d03..041ff37897f05 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -136,6 +136,7 @@
 #![feature(panic_internals)]
 #![feature(pattern)]
 #![feature(pin_coerce_unsized_trait)]
+#![feature(pointer_like_trait)]
 #![feature(ptr_internals)]
 #![feature(ptr_metadata)]
 #![feature(ptr_sub_ptr)]
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 1c5c58d64a2b2..c8ea52a1fb0b4 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -981,6 +981,18 @@ pub trait Tuple {}
 )]
 pub trait PointerLike {}
 
+#[cfg(not(bootstrap))]
+marker_impls! {
+    #[unstable(feature = "pointer_like_trait", issue = "none")]
+    PointerLike for
+        usize,
+        {T} &T,
+        {T} &mut T,
+        {T} *const T,
+        {T} *mut T,
+        {T: PointerLike} crate::pin::Pin<T>,
+}
+
 /// A marker for types which can be used as types of `const` generic parameters.
 ///
 /// These types must have a proper equivalence relation (`Eq`) and it must be automatically
diff --git a/tests/crashes/113280.rs b/tests/crashes/113280.rs
deleted file mode 100644
index 86677f416fe20..0000000000000
--- a/tests/crashes/113280.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-//@ known-bug: #113280
-//@ only-x86_64
-
-#![feature(dyn_star, pointer_like_trait)]
-#![allow(incomplete_features)]
-
-use std::fmt::Debug;
-use std::marker::PointerLike;
-
-fn make_dyn_star<'a>(t: impl PointerLike + Debug + 'a) -> dyn* Debug + 'a {
-    f32::from_bits(0x1) as f64
-}
-
-fn main() {
-    println!("{:?}", make_dyn_star(Box::new(1i32)));
-}
diff --git a/tests/crashes/127676.rs b/tests/crashes/127676.rs
deleted file mode 100644
index 81149c2ef84ae..0000000000000
--- a/tests/crashes/127676.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ known-bug: #127676
-//@ edition:2018
-
-#![feature(dyn_star,const_async_blocks)]
-
-static S: dyn* Send + Sync = async { 42 };
-
-pub fn main() {}
diff --git a/tests/ui/dyn-star/async-block-dyn-star.rs b/tests/ui/dyn-star/async-block-dyn-star.rs
new file mode 100644
index 0000000000000..9bffd6c672539
--- /dev/null
+++ b/tests/ui/dyn-star/async-block-dyn-star.rs
@@ -0,0 +1,9 @@
+//@ edition:2018
+
+#![feature(dyn_star, const_async_blocks)]
+//~^ WARN the feature `dyn_star` is incomplete
+
+static S: dyn* Send + Sync = async { 42 };
+//~^ needs to have the same ABI as a pointer
+
+pub fn main() {}
diff --git a/tests/ui/dyn-star/async-block-dyn-star.stderr b/tests/ui/dyn-star/async-block-dyn-star.stderr
new file mode 100644
index 0000000000000..f62c85c0ad202
--- /dev/null
+++ b/tests/ui/dyn-star/async-block-dyn-star.stderr
@@ -0,0 +1,20 @@
+warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/async-block-dyn-star.rs:3:12
+   |
+LL | #![feature(dyn_star, const_async_blocks)]
+   |            ^^^^^^^^
+   |
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` needs to have the same ABI as a pointer
+  --> $DIR/async-block-dyn-star.rs:6:30
+   |
+LL | static S: dyn* Send + Sync = async { 42 };
+   |                              ^^^^^^^^^^^^ `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` needs to be a pointer-like type
+   |
+   = help: the trait `PointerLike` is not implemented for `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}`
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr
index 7b5ea7bb707ee..a0aff69f39681 100644
--- a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr
+++ b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr
@@ -1,14 +1,17 @@
 error[E0277]: `&T` needs to have the same ABI as a pointer
   --> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15
    |
+LL | fn polymorphic<T: Debug + ?Sized>(t: &T) {
+   |                - this type parameter needs to be `Sized`
 LL |     dyn_debug(t);
    |               ^ `&T` needs to be a pointer-like type
    |
-   = help: the trait `PointerLike` is not implemented for `&T`
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   = note: required for `&T` to implement `PointerLike`
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - fn polymorphic<T: Debug + ?Sized>(t: &T) {
+LL + fn polymorphic<T: Debug>(t: &T) {
    |
-LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerLike {
-   |                                          +++++++++++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr
index 7b5ea7bb707ee..a0aff69f39681 100644
--- a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr
+++ b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr
@@ -1,14 +1,17 @@
 error[E0277]: `&T` needs to have the same ABI as a pointer
   --> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15
    |
+LL | fn polymorphic<T: Debug + ?Sized>(t: &T) {
+   |                - this type parameter needs to be `Sized`
 LL |     dyn_debug(t);
    |               ^ `&T` needs to be a pointer-like type
    |
-   = help: the trait `PointerLike` is not implemented for `&T`
-help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+   = note: required for `&T` to implement `PointerLike`
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - fn polymorphic<T: Debug + ?Sized>(t: &T) {
+LL + fn polymorphic<T: Debug>(t: &T) {
    |
-LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerLike {
-   |                                          +++++++++++++++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/dyn-star/drop.rs b/tests/ui/dyn-star/drop.rs
index ca86f1b5b01f0..bc74633152754 100644
--- a/tests/ui/dyn-star/drop.rs
+++ b/tests/ui/dyn-star/drop.rs
@@ -1,13 +1,18 @@
 //@ run-pass
 //@ check-run-results
-#![feature(dyn_star)]
+#![feature(dyn_star, pointer_like_trait)]
 #![allow(incomplete_features)]
 
 use std::fmt::Debug;
+use std::marker::PointerLike;
 
 #[derive(Debug)]
+#[repr(transparent)]
 struct Foo(#[allow(dead_code)] usize);
 
+// FIXME(dyn_star): Make this into a derive.
+impl PointerLike for Foo {}
+
 impl Drop for Foo {
     fn drop(&mut self) {
         println!("destructor called");
diff --git a/tests/ui/dyn-star/enum-cast.rs b/tests/ui/dyn-star/enum-cast.rs
index 6e895e9527aba..3cc7390eb1280 100644
--- a/tests/ui/dyn-star/enum-cast.rs
+++ b/tests/ui/dyn-star/enum-cast.rs
@@ -3,13 +3,18 @@
 // This used to ICE, because the compiler confused a pointer-like to dyn* coercion
 // with a c-like enum to integer cast.
 
-#![feature(dyn_star)]
+#![feature(dyn_star, pointer_like_trait)]
 #![expect(incomplete_features)]
 
+use std::marker::PointerLike;
+
+#[repr(transparent)]
 enum E {
     Num(usize),
 }
 
+impl PointerLike for E {}
+
 trait Trait {}
 impl Trait for E {}
 
diff --git a/tests/ui/dyn-star/error.rs b/tests/ui/dyn-star/error.rs
index d8261387efa9e..7288596f3fa8a 100644
--- a/tests/ui/dyn-star/error.rs
+++ b/tests/ui/dyn-star/error.rs
@@ -7,7 +7,7 @@ trait Foo {}
 
 fn make_dyn_star() {
     let i = 42;
-    let dyn_i: dyn* Foo = i; //~ ERROR trait bound `{integer}: Foo` is not satisfied
+    let dyn_i: dyn* Foo = i; //~ ERROR trait bound `usize: Foo` is not satisfied
 }
 
 fn main() {}
diff --git a/tests/ui/dyn-star/error.stderr b/tests/ui/dyn-star/error.stderr
index a9f4a05451927..55981c03bac2b 100644
--- a/tests/ui/dyn-star/error.stderr
+++ b/tests/ui/dyn-star/error.stderr
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `{integer}: Foo` is not satisfied
+error[E0277]: the trait bound `usize: Foo` is not satisfied
   --> $DIR/error.rs:10:27
    |
 LL |     let dyn_i: dyn* Foo = i;
-   |                           ^ the trait `Foo` is not implemented for `{integer}`
+   |                           ^ the trait `Foo` is not implemented for `usize`
    |
 help: this trait has no implementations, consider adding one
   --> $DIR/error.rs:6:1
diff --git a/tests/ui/dyn-star/float-as-dyn-star.rs b/tests/ui/dyn-star/float-as-dyn-star.rs
new file mode 100644
index 0000000000000..1b629c64c25a9
--- /dev/null
+++ b/tests/ui/dyn-star/float-as-dyn-star.rs
@@ -0,0 +1,16 @@
+//@ only-x86_64
+
+#![feature(dyn_star, pointer_like_trait)]
+//~^ WARN the feature `dyn_star` is incomplete
+
+use std::fmt::Debug;
+use std::marker::PointerLike;
+
+fn make_dyn_star() -> dyn* Debug + 'static {
+    f32::from_bits(0x1) as f64
+    //~^ ERROR `f64` needs to have the same ABI as a pointer
+}
+
+fn main() {
+    println!("{:?}", make_dyn_star());
+}
diff --git a/tests/ui/dyn-star/float-as-dyn-star.stderr b/tests/ui/dyn-star/float-as-dyn-star.stderr
new file mode 100644
index 0000000000000..9caba512e5f43
--- /dev/null
+++ b/tests/ui/dyn-star/float-as-dyn-star.stderr
@@ -0,0 +1,21 @@
+warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/float-as-dyn-star.rs:3:12
+   |
+LL | #![feature(dyn_star, pointer_like_trait)]
+   |            ^^^^^^^^
+   |
+   = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: `f64` needs to have the same ABI as a pointer
+  --> $DIR/float-as-dyn-star.rs:10:5
+   |
+LL |     f32::from_bits(0x1) as f64
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ `f64` needs to be a pointer-like type
+   |
+   = help: the trait `PointerLike` is not implemented for `f64`
+   = help: the trait `PointerLike` is implemented for `usize`
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/dyn-star/upcast.stderr b/tests/ui/dyn-star/upcast.stderr
index adef9525bf1fa..801e1c233c1ae 100644
--- a/tests/ui/dyn-star/upcast.stderr
+++ b/tests/ui/dyn-star/upcast.stderr
@@ -7,6 +7,14 @@ LL | #![feature(dyn_star, trait_upcasting)]
    = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
+error[E0277]: `W` needs to have the same ABI as a pointer
+  --> $DIR/upcast.rs:28:23
+   |
+LL |     let w: dyn* Foo = W(0);
+   |                       ^^^^ `W` needs to be a pointer-like type
+   |
+   = help: the trait `PointerLike` is not implemented for `W`
+
 error[E0277]: `dyn* Foo` needs to have the same ABI as a pointer
   --> $DIR/upcast.rs:30:23
    |
@@ -15,6 +23,6 @@ LL |     let w: dyn* Bar = w;
    |
    = help: the trait `PointerLike` is not implemented for `dyn* Foo`
 
-error: aborting due to 1 previous error; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0277`.

From 186e282a43f384d456579ab50c5d6a48fd5cca1b Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Wed, 20 Nov 2024 18:11:37 +0100
Subject: [PATCH 16/16] Add `UnordMap::clear` method

---
 compiler/rustc_data_structures/src/unord.rs | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs
index bafb16a8b5e67..34895d3efe6ca 100644
--- a/compiler/rustc_data_structures/src/unord.rs
+++ b/compiler/rustc_data_structures/src/unord.rs
@@ -602,6 +602,11 @@ impl<K: Eq + Hash, V> UnordMap<K, V> {
             .into_iter()
             .map(|(_, v)| v)
     }
+
+    #[inline]
+    pub fn clear(&mut self) {
+        self.inner.clear()
+    }
 }
 
 impl<K, Q: ?Sized, V> Index<&Q> for UnordMap<K, V>