From cc2ed5ae136fc1b0f6a0132b9623d5a837ded306 Mon Sep 17 00:00:00 2001
From: xizheyin <xizheyin@smail.nju.edu.cn>
Date: Mon, 17 Mar 2025 22:22:32 +0800
Subject: [PATCH 01/17] Report span of test when should_panic test failed

Signed-off-by: xizheyin <xizheyin@smail.nju.edu.cn>
---
 library/test/src/test_result.rs               |  8 +++-
 .../failed-doctest-should-panic.stdout        |  2 +-
 .../ui/test-should-panic-failed-show-span.rs  | 41 +++++++++++++++++++
 ...t-should-panic-failed-show-span.run.stdout | 38 +++++++++++++++++
 .../test-should-panic-failed-show-span.stderr | 21 ++++++++++
 5 files changed, 108 insertions(+), 2 deletions(-)
 create mode 100644 tests/ui/test-should-panic-failed-show-span.rs
 create mode 100644 tests/ui/test-should-panic-failed-show-span.run.stdout
 create mode 100644 tests/ui/test-should-panic-failed-show-span.stderr

diff --git a/library/test/src/test_result.rs b/library/test/src/test_result.rs
index 73dcc2e2a0cca..3fdb4f0d3d2b7 100644
--- a/library/test/src/test_result.rs
+++ b/library/test/src/test_result.rs
@@ -45,6 +45,12 @@ pub(crate) fn calc_result<'a>(
     time_opts: Option<&time::TestTimeOptions>,
     exec_time: Option<&time::TestExecTime>,
 ) -> TestResult {
+    let fn_location = if !desc.source_file.is_empty() {
+        &format!(" at {}:{}:{}", desc.source_file, desc.start_line, desc.start_col)
+    } else {
+        ""
+    };
+
     let result = match (&desc.should_panic, task_result) {
         (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TestResult::TrOk,
         (&ShouldPanic::YesWithMessage(msg), Err(err)) => {
@@ -72,7 +78,7 @@ pub(crate) fn calc_result<'a>(
             }
         }
         (&ShouldPanic::Yes, Ok(())) | (&ShouldPanic::YesWithMessage(_), Ok(())) => {
-            TestResult::TrFailedMsg("test did not panic as expected".to_string())
+            TestResult::TrFailedMsg(format!("test did not panic as expected{}", fn_location))
         }
         _ => TestResult::TrFailed,
     };
diff --git a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout
index 90c0463d832e1..2b04b77c9dc5c 100644
--- a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout
+++ b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout
@@ -5,7 +5,7 @@ test $DIR/failed-doctest-should-panic.rs - Foo (line 10) - should panic ... FAIL
 failures:
 
 ---- $DIR/failed-doctest-should-panic.rs - Foo (line 10) stdout ----
-note: test did not panic as expected
+note: test did not panic as expected at $DIR/failed-doctest-should-panic.rs:10:0
 
 failures:
     $DIR/failed-doctest-should-panic.rs - Foo (line 10)
diff --git a/tests/ui/test-should-panic-failed-show-span.rs b/tests/ui/test-should-panic-failed-show-span.rs
new file mode 100644
index 0000000000000..e99bc7754ccce
--- /dev/null
+++ b/tests/ui/test-should-panic-failed-show-span.rs
@@ -0,0 +1,41 @@
+//@ run-fail
+//@ check-run-results
+//@ compile-flags: --test
+//@ run-flags: --test-threads=1
+
+#[test]
+#[should_panic]
+fn should_panic_with_any_message() {
+    panic!("Panic!");
+}
+
+#[test]
+#[should_panic = "message"]
+fn should_panic_with_message() {
+    panic!("message");
+}
+
+#[test]
+#[should_panic]
+fn should_panic_with_any_message_does_not_panic() {
+    // DON'T PANIC
+}
+
+
+#[test]
+#[should_panic = "message"]
+fn should_panic_with_message_does_not_panic() {
+    // DON'T PANIC
+}
+
+#[test]
+#[should_panic = "message"]
+fn should_panic_with_substring_panics_with_incorrect_string() {
+    panic!("ZOMGWTFBBQ");
+}
+
+#[test]
+#[should_panic = "message"]
+fn should_panic_with_substring_panics_with_non_string_value() {
+    panic!(123); //~ WARNING panic message is not a string literal
+}
diff --git a/tests/ui/test-should-panic-failed-show-span.run.stdout b/tests/ui/test-should-panic-failed-show-span.run.stdout
new file mode 100644
index 0000000000000..ef8c56c485a69
--- /dev/null
+++ b/tests/ui/test-should-panic-failed-show-span.run.stdout
@@ -0,0 +1,38 @@
+
+running 6 tests
+test should_panic_with_any_message - should panic ... ok
+test should_panic_with_any_message_does_not_panic - should panic ... FAILED
+test should_panic_with_message - should panic ... ok
+test should_panic_with_message_does_not_panic - should panic ... FAILED
+test should_panic_with_substring_panics_with_incorrect_string - should panic ... FAILED
+test should_panic_with_substring_panics_with_non_string_value - should panic ... FAILED
+
+failures:
+
+---- should_panic_with_any_message_does_not_panic stdout ----
+note: test did not panic as expected at $DIR/test-should-panic-failed-show-span.rs:20:4
+---- should_panic_with_message_does_not_panic stdout ----
+note: test did not panic as expected at $DIR/test-should-panic-failed-show-span.rs:27:4
+---- should_panic_with_substring_panics_with_incorrect_string stdout ----
+
+thread 'should_panic_with_substring_panics_with_incorrect_string' panicked at $DIR/test-should-panic-failed-show-span.rs:34:5:
+ZOMGWTFBBQ
+note: panic did not contain expected string
+      panic message: `"ZOMGWTFBBQ"`,
+ expected substring: `"message"`
+---- should_panic_with_substring_panics_with_non_string_value stdout ----
+
+thread 'should_panic_with_substring_panics_with_non_string_value' panicked at $DIR/test-should-panic-failed-show-span.rs:40:5:
+Box<dyn Any>
+note: expected panic with string value,
+ found non-string value: `TypeId(0x56ced5e4a15bd89050bb9674fa2df013)`
+     expected substring: `"message"`
+
+failures:
+    should_panic_with_any_message_does_not_panic
+    should_panic_with_message_does_not_panic
+    should_panic_with_substring_panics_with_incorrect_string
+    should_panic_with_substring_panics_with_non_string_value
+
+test result: FAILED. 2 passed; 4 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
+
diff --git a/tests/ui/test-should-panic-failed-show-span.stderr b/tests/ui/test-should-panic-failed-show-span.stderr
new file mode 100644
index 0000000000000..c50628d6b5edb
--- /dev/null
+++ b/tests/ui/test-should-panic-failed-show-span.stderr
@@ -0,0 +1,21 @@
+warning: panic message is not a string literal
+  --> $DIR/test-should-panic-failed-show-span.rs:40:12
+   |
+LL |     panic!(123);
+   |            ^^^
+   |
+   = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+   = note: `#[warn(non_fmt_panics)]` on by default
+help: add a "{}" format string to `Display` the message
+   |
+LL |     panic!("{}", 123);
+   |            +++++
+help: or use std::panic::panic_any instead
+   |
+LL -     panic!(123);
+LL +     std::panic::panic_any(123);
+   |
+
+warning: 1 warning emitted
+

From 9f089e080c47bc282aa98f1e8c72ff44076afbb9 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <n.nethercote@gmail.com>
Date: Thu, 27 Mar 2025 09:33:02 +1100
Subject: [PATCH 02/17] Add `{ast,hir,thir}::PatKind::Missing` variants.

"Missing" patterns are possible in bare fn types (`fn f(u32)`) and
similar places. Currently these are represented in the AST with
`ast::PatKind::Ident` with no `by_ref`, no `mut`, an empty ident, and no
sub-pattern. This flows through to `{hir,thir}::PatKind::Binding` for
HIR and THIR.

This is a bit nasty. It's very non-obvious, and easy to forget to check
for the exceptional empty identifier case.

This commit adds a new variant, `PatKind::Missing`, to do it properly.

The process I followed:
- Add a `Missing` variant to `{ast,hir,thir}::PatKind`.
- Chang `parse_param_general` to produce `ast::PatKind::Missing`
  instead of `ast::PatKind::Missing`.
- Look through `kw::Empty` occurrences to find functions where an
  existing empty ident check needs replacing with a `PatKind::Missing`
  check: `print_param`, `check_trait_item`, `is_named_param`.
- Add a `PatKind::Missing => unreachable!(),` arm to every exhaustive
  match identified by the compiler.
- Find which arms are actually reachable by running the test suite,
  changing them to something appropriate, usually by looking at what
  would happen to a `PatKind::Ident`/`PatKind::Binding` with no ref, no
  `mut`, an empty ident, and no subpattern.

Quite a few of the `unreachable!()` arms were never reached. This makes
sense because `PatKind::Missing` can't happen in every pattern, only
in places like bare fn tys and trait fn decls.

I also tried an alternative approach: modifying `ast::Param::pat` to
hold an `Option<P<Pat>>` instead of a `P<Pat>`, but that quickly turned
into a very large and painful change. Adding `PatKind::Missing` is much
easier.
---
 compiler/rustc_ast/src/ast.rs                 |  8 +++++-
 compiler/rustc_ast/src/mut_visit.rs           |  2 +-
 compiler/rustc_ast/src/visit.rs               |  2 +-
 compiler/rustc_ast_lowering/src/lib.rs        |  3 ++-
 compiler/rustc_ast_lowering/src/pat.rs        |  1 +
 .../rustc_ast_passes/src/ast_validation.rs    |  2 +-
 compiler/rustc_ast_pretty/src/pprust/state.rs | 11 +++-----
 compiler/rustc_hir/src/hir.rs                 |  6 ++++-
 compiler/rustc_hir/src/intravisit.rs          |  2 +-
 .../rustc_hir_analysis/src/check/region.rs    |  1 +
 compiler/rustc_hir_pretty/src/lib.rs          |  1 +
 compiler/rustc_hir_typeck/src/expr.rs         |  3 ++-
 .../rustc_hir_typeck/src/expr_use_visitor.rs  |  2 ++
 compiler/rustc_hir_typeck/src/pat.rs          | 11 +++++---
 compiler/rustc_lint/src/builtin.rs            | 26 +++++++++----------
 compiler/rustc_lint/src/unused.rs             |  3 ++-
 compiler/rustc_middle/src/thir.rs             |  3 +++
 compiler/rustc_middle/src/thir/visit.rs       |  3 ++-
 .../src/builder/matches/match_pair.rs         |  2 +-
 .../src/builder/matches/mod.rs                |  1 +
 .../rustc_mir_build/src/check_unsafety.rs     |  1 +
 .../rustc_mir_build/src/thir/pattern/mod.rs   |  2 ++
 compiler/rustc_mir_build/src/thir/print.rs    |  1 +
 compiler/rustc_parse/src/parser/item.rs       |  4 +--
 compiler/rustc_passes/src/input_stats.rs      |  2 ++
 compiler/rustc_pattern_analysis/src/rustc.rs  |  2 +-
 src/librustdoc/clean/utils.rs                 |  1 +
 .../clippy_lints/src/equatable_if_let.rs      |  1 +
 .../src/matches/match_same_arms.rs            |  1 +
 .../clippy_lints/src/matches/single_match.rs  |  1 +
 .../clippy_lints/src/unnested_or_patterns.rs  |  1 +
 .../clippy/clippy_lints/src/utils/author.rs   |  1 +
 .../clippy/clippy_utils/src/ast_utils/mod.rs  |  1 +
 .../clippy/clippy_utils/src/hir_utils.rs      |  1 +
 src/tools/clippy/clippy_utils/src/lib.rs      |  1 +
 src/tools/rustfmt/src/items.rs                |  6 +----
 src/tools/rustfmt/src/patterns.rs             |  2 ++
 tests/ui/macros/stringify.rs                  |  2 ++
 tests/ui/unpretty/expanded-exhaustive.rs      |  5 ++++
 tests/ui/unpretty/expanded-exhaustive.stdout  |  3 +++
 40 files changed, 86 insertions(+), 46 deletions(-)

diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 064f05ef1f3ef..944ae65ffc679 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -563,6 +563,7 @@ impl Pat {
     /// This is intended for use by diagnostics.
     pub fn to_ty(&self) -> Option<P<Ty>> {
         let kind = match &self.kind {
+            PatKind::Missing => unreachable!(),
             // In a type expression `_` is an inference variable.
             PatKind::Wild => TyKind::Infer,
             // An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`.
@@ -625,7 +626,8 @@ impl Pat {
             | PatKind::Guard(s, _) => s.walk(it),
 
             // These patterns do not contain subpatterns, skip.
-            PatKind::Wild
+            PatKind::Missing
+            | PatKind::Wild
             | PatKind::Rest
             | PatKind::Never
             | PatKind::Expr(_)
@@ -676,6 +678,7 @@ impl Pat {
     /// Return a name suitable for diagnostics.
     pub fn descr(&self) -> Option<String> {
         match &self.kind {
+            PatKind::Missing => unreachable!(),
             PatKind::Wild => Some("_".to_string()),
             PatKind::Ident(BindingMode::NONE, ident, None) => Some(format!("{ident}")),
             PatKind::Ref(pat, mutbl) => pat.descr().map(|d| format!("&{}{d}", mutbl.prefix_str())),
@@ -769,6 +772,9 @@ pub enum RangeSyntax {
 // Adding a new variant? Please update `test_pat` in `tests/ui/macros/stringify.rs`.
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub enum PatKind {
+    /// A missing pattern, e.g. for an anonymous param in a bare fn like `fn f(u32)`.
+    Missing,
+
     /// Represents a wildcard pattern (`_`).
     Wild,
 
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 274fe312f7fad..8c6ddf2a69c9a 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1572,7 +1572,7 @@ pub fn walk_pat<T: MutVisitor>(vis: &mut T, pat: &mut P<Pat>) {
     vis.visit_id(id);
     match kind {
         PatKind::Err(_guar) => {}
-        PatKind::Wild | PatKind::Rest | PatKind::Never => {}
+        PatKind::Missing | PatKind::Wild | PatKind::Rest | PatKind::Never => {}
         PatKind::Ident(_binding_mode, ident, sub) => {
             vis.visit_ident(ident);
             visit_opt(sub, |sub| vis.visit_pat(sub));
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 2716601ca4f9d..3d78f65f634bf 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -727,7 +727,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
             try_visit!(visitor.visit_pat(subpattern));
             try_visit!(visitor.visit_expr(guard_condition));
         }
-        PatKind::Wild | PatKind::Rest | PatKind::Never => {}
+        PatKind::Missing | PatKind::Wild | PatKind::Rest | PatKind::Never => {}
         PatKind::Err(_guar) => {}
         PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
             walk_list!(visitor, visit_pat, elems);
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index ced9064fd9f41..4041e5d092aa8 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1495,6 +1495,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
     fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Option<Ident>] {
         self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind {
+            PatKind::Missing => None,
             PatKind::Ident(_, ident, _) => {
                 if ident.name != kw::Empty {
                     Some(self.lower_ident(ident))
@@ -1506,7 +1507,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             _ => {
                 self.dcx().span_delayed_bug(
                     param.pat.span,
-                    "non-ident/wild param pat must trigger an error",
+                    "non-missing/ident/wild param pat must trigger an error",
                 );
                 None
             }
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 07cc64a1358ee..f94d788a9b0e6 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -26,6 +26,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             let pat_hir_id = self.lower_node_id(pattern.id);
             let node = loop {
                 match &pattern.kind {
+                    PatKind::Missing => break hir::PatKind::Missing,
                     PatKind::Wild => break hir::PatKind::Wild,
                     PatKind::Never => break hir::PatKind::Never,
                     PatKind::Ident(binding_mode, ident, sub) => {
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index a1487ca74be87..ab6d4644f7e94 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -239,7 +239,7 @@ impl<'a> AstValidator<'a> {
     fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
         for Param { pat, .. } in &decl.inputs {
             match pat.kind {
-                PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {}
+                PatKind::Missing | PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {}
                 PatKind::Ident(BindingMode::MUT, ident, None) => {
                     report_err(pat.span, Some(ident), true)
                 }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index cdb1817944987..f9e17fb0539d8 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1622,9 +1622,9 @@ impl<'a> State<'a> {
     fn print_pat(&mut self, pat: &ast::Pat) {
         self.maybe_print_comment(pat.span.lo());
         self.ann.pre(self, AnnNode::Pat(pat));
-        /* Pat isn't normalized, but the beauty of it
-        is that it doesn't matter */
+        /* Pat isn't normalized, but the beauty of it is that it doesn't matter */
         match &pat.kind {
+            PatKind::Missing => unreachable!(),
             PatKind::Wild => self.word("_"),
             PatKind::Never => self.word("!"),
             PatKind::Ident(BindingMode(by_ref, mutbl), ident, sub) => {
@@ -1946,12 +1946,7 @@ impl<'a> State<'a> {
                 if let Some(eself) = input.to_self() {
                     self.print_explicit_self(&eself);
                 } else {
-                    let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind {
-                        ident.name == kw::Empty
-                    } else {
-                        false
-                    };
-                    if !invalid {
+                    if !matches!(input.pat.kind, PatKind::Missing) {
                         self.print_pat(&input.pat);
                         self.word(":");
                         self.space();
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 751c379b21a64..08e37accb8a30 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1516,6 +1516,7 @@ impl<'hir> Pat<'hir> {
 
         use PatKind::*;
         match self.kind {
+            Missing => unreachable!(),
             Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => true,
             Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it),
             Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
@@ -1543,7 +1544,7 @@ impl<'hir> Pat<'hir> {
 
         use PatKind::*;
         match self.kind {
-            Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => {}
+            Missing | Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => {}
             Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it),
             Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
             TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
@@ -1681,6 +1682,9 @@ pub enum TyPatKind<'hir> {
 
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub enum PatKind<'hir> {
+    /// A missing pattern, e.g. for an anonymous param in a bare fn like `fn f(u32)`.
+    Missing,
+
     /// Represents a wildcard pattern (i.e., `_`).
     Wild,
 
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 506358341b501..ea3f396761b16 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -744,7 +744,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
             visit_opt!(visitor, visit_pat_expr, lower_bound);
             visit_opt!(visitor, visit_pat_expr, upper_bound);
         }
-        PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
+        PatKind::Missing | PatKind::Never | PatKind::Wild | PatKind::Err(_) => (),
         PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => {
             walk_list!(visitor, visit_pat, prepatterns);
             visit_opt!(visitor, visit_pat, slice_pattern);
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 255f5fee52a80..d63fef8c0ef26 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -701,6 +701,7 @@ fn resolve_local<'tcx>(
 
             PatKind::Ref(_, _)
             | PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..)
+            | PatKind::Missing
             | PatKind::Wild
             | PatKind::Never
             | PatKind::Expr(_)
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index ddaca89ccf82d..a4961fc2c8506 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1875,6 +1875,7 @@ impl<'a> State<'a> {
         // Pat isn't normalized, but the beauty of it
         // is that it doesn't matter
         match pat.kind {
+            PatKind::Missing => unreachable!(),
             PatKind::Wild => self.word("_"),
             PatKind::Never => self.word("!"),
             PatKind::Binding(BindingMode(by_ref, mutbl), _, ident, sub) => {
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index a75f6f4caac91..0ed03a03c1b48 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -482,7 +482,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             // All of these constitute a read, or match on something that isn't `!`,
             // which would require a `NeverToAny` coercion.
-            hir::PatKind::Binding(_, _, _, _)
+            hir::PatKind::Missing
+            | hir::PatKind::Binding(_, _, _, _)
             | hir::PatKind::Struct(_, _, _)
             | hir::PatKind::TupleStruct(_, _, _)
             | hir::PatKind::Tuple(_, _)
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index c71a5ea8b9761..d50f235ad4d10 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -611,6 +611,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
         for pat in pats {
             self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
                 match &pat.kind {
+                    PatKind::Missing => unreachable!(),
                     PatKind::Binding(.., opt_sub_pat) => {
                         // If the opt_sub_pat is None, then the binding does not count as
                         // a wildcard for the purpose of borrowing discr.
@@ -1884,6 +1885,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
             | PatKind::Expr(..)
             | PatKind::Range(..)
             | PatKind::Never
+            | PatKind::Missing
             | PatKind::Wild
             | PatKind::Err(_) => {
                 // always ok
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index f1f956779c94f..0d4ecbc867b73 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -341,7 +341,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let ty = match pat.kind {
-            PatKind::Wild | PatKind::Err(_) => expected,
+            PatKind::Missing | PatKind::Wild | PatKind::Err(_) => expected,
             // We allow any type here; we ensure that the type is uninhabited during match checking.
             PatKind::Never => expected,
             PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
@@ -505,9 +505,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             },
 
             // Ref patterns are complicated, we handle them in `check_pat_ref`.
-            PatKind::Ref(..) => AdjustMode::Pass,
+            PatKind::Ref(..)
+            // No need to do anything on a missing pattern.
+            | PatKind::Missing
             // A `_` pattern works with any expected type, so there's no need to do anything.
-            PatKind::Wild
+            | PatKind::Wild
             // A malformed pattern doesn't have an expected type, so let's just accept any type.
             | PatKind::Err(_)
             // Bindings also work with whatever the expected type is,
@@ -1037,7 +1039,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         | PatKind::Tuple(..)
                         | PatKind::Slice(..) => "binding",
 
-                        PatKind::Wild
+                        PatKind::Missing
+                        | PatKind::Wild
                         | PatKind::Never
                         | PatKind::Binding(..)
                         | PatKind::Box(..)
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 9dccd4a0552c3..0b5cdf99de5aa 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -778,21 +778,19 @@ impl EarlyLintPass for AnonymousParameters {
         }
         if let ast::AssocItemKind::Fn(box Fn { ref sig, .. }) = it.kind {
             for arg in sig.decl.inputs.iter() {
-                if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
-                    if ident.name == kw::Empty {
-                        let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
+                if let ast::PatKind::Missing = arg.pat.kind {
+                    let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
 
-                        let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
-                            (snip.as_str(), Applicability::MachineApplicable)
-                        } else {
-                            ("<type>", Applicability::HasPlaceholders)
-                        };
-                        cx.emit_span_lint(
-                            ANONYMOUS_PARAMETERS,
-                            arg.pat.span,
-                            BuiltinAnonymousParams { suggestion: (arg.pat.span, appl), ty_snip },
-                        );
-                    }
+                    let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
+                        (snip.as_str(), Applicability::MachineApplicable)
+                    } else {
+                        ("<type>", Applicability::HasPlaceholders)
+                    };
+                    cx.emit_span_lint(
+                        ANONYMOUS_PARAMETERS,
+                        arg.pat.span,
+                        BuiltinAnonymousParams { suggestion: (arg.pat.span, appl), ty_snip },
+                    );
                 }
             }
         }
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 7b43aac90c741..806bca78f7875 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -1201,7 +1201,8 @@ impl EarlyLintPass for UnusedParens {
             // Do not lint on `(..)` as that will result in the other arms being useless.
             Paren(_)
             // The other cases do not contain sub-patterns.
-            | Wild | Never | Rest | Expr(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) | Err(_) => {},
+            | Missing | Wild | Never | Rest | Expr(..) | MacCall(..) | Range(..) | Ident(.., None)
+            | Path(..) | Err(_) => {},
             // These are list-like patterns; parens can always be removed.
             TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
                 self.check_unused_parens_pat(cx, p, false, false, keep_space);
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 6783bbf8bf42f..413717e45ebfa 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -747,6 +747,9 @@ pub struct Ascription<'tcx> {
 
 #[derive(Clone, Debug, HashStable, TypeVisitable)]
 pub enum PatKind<'tcx> {
+    /// A missing pattern, e.g. for an anonymous param in a bare fn like `fn f(u32)`.
+    Missing,
+
     /// A wildcard pattern: `_`.
     Wild,
 
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 7d62ab7970d01..f3da2a5cc8e4e 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -250,7 +250,8 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>(
     mut callback: impl FnMut(&'a Pat<'tcx>),
 ) {
     match &pat.kind {
-        PatKind::Wild
+        PatKind::Missing
+        | PatKind::Wild
         | PatKind::Binding { subpattern: None, .. }
         | PatKind::Constant { value: _ }
         | PatKind::Range(_)
diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
index 29d400a957b47..11672163b658f 100644
--- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
@@ -118,7 +118,7 @@ impl<'tcx> MatchPairTree<'tcx> {
         let place = place_builder.try_to_place(cx);
         let mut subpairs = Vec::new();
         let test_case = match pattern.kind {
-            PatKind::Wild | PatKind::Error(_) => None,
+            PatKind::Missing | PatKind::Wild | PatKind::Error(_) => None,
 
             PatKind::Or { ref pats } => Some(TestCase::Or {
                 pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(),
diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs
index 3acf2a6a2a61a..977d4f3e931b5 100644
--- a/compiler/rustc_mir_build/src/builder/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs
@@ -920,6 +920,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
             PatKind::Constant { .. }
             | PatKind::Range { .. }
+            | PatKind::Missing
             | PatKind::Wild
             | PatKind::Never
             | PatKind::Error(_) => {}
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 7f2e7d5ca8385..9572dfc52dac8 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -313,6 +313,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
     fn visit_pat(&mut self, pat: &'a Pat<'tcx>) {
         if self.in_union_destructure {
             match pat.kind {
+                PatKind::Missing => unreachable!(),
                 // binding to a variable allows getting stuff out of variable
                 PatKind::Binding { .. }
                 // match is conditional on having this value
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 4bfeab44bf4b9..f36a895849a14 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -290,6 +290,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         let mut span = pat.span;
 
         let kind = match pat.kind {
+            hir::PatKind::Missing => PatKind::Missing,
+
             hir::PatKind::Wild => PatKind::Wild,
 
             hir::PatKind::Never => PatKind::Never,
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index 16cef0ec3acbc..ac71bb845a886 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -664,6 +664,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
         print_indented!(self, "kind: PatKind {", depth_lvl);
 
         match pat_kind {
+            PatKind::Missing => unreachable!(),
             PatKind::Wild => {
                 print_indented!(self, "Wild", depth_lvl + 1);
             }
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index aad1857837554..0f5d8d9fbedd4 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -2941,9 +2941,7 @@ impl<'a> Parser<'a> {
                 }
                 match ty {
                     Ok(ty) => {
-                        let ident = Ident::new(kw::Empty, this.prev_token.span);
-                        let bm = BindingMode::NONE;
-                        let pat = this.mk_pat_ident(ty.span, bm, ident);
+                        let pat = this.mk_pat(ty.span, PatKind::Missing);
                         (pat, ty)
                     }
                     // If this is a C-variadic argument and we hit an error, return the error.
diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs
index 1278e98afcf61..7181544817225 100644
--- a/compiler/rustc_passes/src/input_stats.rs
+++ b/compiler/rustc_passes/src/input_stats.rs
@@ -295,6 +295,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         record_variants!(
             (self, p, p.kind, Some(p.hir_id), hir, Pat, PatKind),
             [
+                Missing,
                 Wild,
                 Binding,
                 Struct,
@@ -597,6 +598,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
         record_variants!(
             (self, p, p.kind, None, ast, Pat, PatKind),
             [
+                Missing,
                 Wild,
                 Ident,
                 Struct,
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index a25a80cd45f74..e815273405244 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -457,7 +457,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
             PatKind::AscribeUserType { 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 => {
+            PatKind::Missing | PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
                 ctor = Wildcard;
                 fields = vec![];
                 arity = 0;
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index f81db58950cbd..afcca81a485ff 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -304,6 +304,7 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
 
     Symbol::intern(&match &p.kind {
         // FIXME(never_patterns): does this make sense?
+        PatKind::Missing => unreachable!(),
         PatKind::Wild
         | PatKind::Err(_)
         | PatKind::Never
diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
index cd9ab2764ac48..3afb687040f45 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -45,6 +45,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
         pats.iter().all(unary_pattern)
     }
     match &pat.kind {
+        PatKind::Missing => unreachable!(),
         PatKind::Slice(_, _, _)
         | PatKind::Range(_, _, _)
         | PatKind::Binding(..)
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index 250f17fa9025a..a21597ffb93d7 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -253,6 +253,7 @@ fn iter_matching_struct_fields<'a>(
 impl<'a> NormalizedPat<'a> {
     fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self {
         match pat.kind {
+            PatKind::Missing => unreachable!(),
             PatKind::Wild | PatKind::Binding(.., None) => Self::Wild,
             PatKind::Binding(.., Some(pat))
             | PatKind::Box(pat)
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index 56fbd626eefc4..836c46240ce7b 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -406,6 +406,7 @@ impl<'a> PatState<'a> {
                 pats.iter().map(|p| p.pat),
             ),
 
+            PatKind::Missing => unreachable!(),
             PatKind::Wild
             | PatKind::Binding(_, _, _, None)
             | PatKind::Expr(_)
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index f43715d6752e3..8966e6851ac2f 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -224,6 +224,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
 
     // We're trying to find whatever kind (~"constructor") we found in `alternatives[start..]`.
     let changed = match &mut focus_kind {
+        Missing => unreachable!(),
         // These pattern forms are "leafs" and do not have sub-patterns.
         // Therefore they are not some form of constructor `C`,
         // with which a pattern `C(p_0)` may be formed,
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 4309cd2c9abdf..b7dcd2ffb0eea 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -676,6 +676,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
         }
 
         match pat.value.kind {
+            PatKind::Missing => unreachable!(),
             PatKind::Wild => kind!("Wild"),
             PatKind::Never => kind!("Never"),
             PatKind::Binding(ann, _, name, sub) => {
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
index 6023ae9cc7b16..ed99f966d2b76 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
@@ -33,6 +33,7 @@ pub fn eq_id(l: Ident, r: Ident) -> bool {
 pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
     use PatKind::*;
     match (&l.kind, &r.kind) {
+        (Missing, _) | (_, Missing) => unreachable!(),
         (Paren(l), _) => eq_pat(l, r),
         (_, Paren(r)) => eq_pat(l, r),
         (Wild, Wild) | (Rest, Rest) => true,
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 9938e64d24264..b813cd361ed8c 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1124,6 +1124,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
     pub fn hash_pat(&mut self, pat: &Pat<'_>) {
         std::mem::discriminant(&pat.kind).hash(&mut self.s);
         match pat.kind {
+            PatKind::Missing => unreachable!(),
             PatKind::Binding(BindingMode(by_ref, mutability), _, _, pat) => {
                 std::mem::discriminant(&by_ref).hash(&mut self.s);
                 std::mem::discriminant(&mutability).hash(&mut self.s);
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 1307ff79bc5dd..bdcbe1437d0e2 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1857,6 +1857,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
     }
 
     match pat.kind {
+        PatKind::Missing => unreachable!(),
         PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable.
         PatKind::Binding(_, _, _, pat) => pat.is_some_and(|pat| is_refutable(cx, pat)),
         PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index 3fb3284e3d7fd..81ff6327a4fc0 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -2433,11 +2433,7 @@ pub(crate) fn span_hi_for_param(context: &RewriteContext<'_>, param: &ast::Param
 }
 
 pub(crate) fn is_named_param(param: &ast::Param) -> bool {
-    if let ast::PatKind::Ident(_, ident, _) = param.pat.kind {
-        ident.name != symbol::kw::Empty
-    } else {
-        true
-    }
+    !matches!(param.pat.kind, ast::PatKind::Missing)
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs
index bafed41e39f42..8ec3de286dcb7 100644
--- a/src/tools/rustfmt/src/patterns.rs
+++ b/src/tools/rustfmt/src/patterns.rs
@@ -42,6 +42,7 @@ pub(crate) fn is_short_pattern(
 
 fn is_short_pattern_inner(context: &RewriteContext<'_>, pat: &ast::Pat) -> bool {
     match &pat.kind {
+        ast::PatKind::Missing => unreachable!(),
         ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Err(_) => {
             true
         }
@@ -100,6 +101,7 @@ impl Rewrite for Pat {
 
     fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
         match self.kind {
+            PatKind::Missing => unreachable!(),
             PatKind::Or(ref pats) => {
                 let pat_strs = pats
                     .iter()
diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs
index 40033f546d30b..3490d3efc5992 100644
--- a/tests/ui/macros/stringify.rs
+++ b/tests/ui/macros/stringify.rs
@@ -515,6 +515,8 @@ fn test_meta() {
 
 #[test]
 fn test_pat() {
+    // PatKind::Missing: untestable in isolation.
+
     // PatKind::Wild
     c1!(pat, [ _ ], "_");
 
diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs
index 31af323ecdab5..4d1f12e349001 100644
--- a/tests/ui/unpretty/expanded-exhaustive.rs
+++ b/tests/ui/unpretty/expanded-exhaustive.rs
@@ -574,6 +574,11 @@ mod items {
 }
 
 mod patterns {
+    /// PatKind::Missing
+    fn pat_missing() {
+        let _: fn(u32, T, &str);
+    }
+
     /// PatKind::Wild
     fn pat_wild() {
         let _;
diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout
index 19ae66f7a07aa..d8da941a34077 100644
--- a/tests/ui/unpretty/expanded-exhaustive.stdout
+++ b/tests/ui/unpretty/expanded-exhaustive.stdout
@@ -361,6 +361,7 @@ mod expressions {
 
 
 
+
 
 
         { builtin # offset_of(T, field) };
@@ -517,6 +518,8 @@ mod items {
     }
 }
 mod patterns {
+    /// PatKind::Missing
+    fn pat_missing() { let _: fn(u32, T, &str); }
     /// PatKind::Wild
     fn pat_wild() { let _; }
     /// PatKind::Ident

From 909f4492475988ba5e1b84efadacb16eb7d7ff0e Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <n.nethercote@gmail.com>
Date: Thu, 27 Mar 2025 17:00:27 +1100
Subject: [PATCH 03/17] Remove `kw::Extra` checks that are no longer necessary.

Thanks to the introduction of `PatKind::Missing`.
---
 compiler/rustc_ast_lowering/src/lib.rs |  8 +-------
 compiler/rustc_passes/src/liveness.rs  |  5 +----
 compiler/rustc_resolve/src/late.rs     | 13 ++++---------
 3 files changed, 6 insertions(+), 20 deletions(-)

diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 4041e5d092aa8..a3e0f96031613 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1496,13 +1496,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Option<Ident>] {
         self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind {
             PatKind::Missing => None,
-            PatKind::Ident(_, ident, _) => {
-                if ident.name != kw::Empty {
-                    Some(self.lower_ident(ident))
-                } else {
-                    None
-                }
-            }
+            PatKind::Ident(_, ident, _) => Some(self.lower_ident(ident)),
             PatKind::Wild => Some(Ident::new(kw::Underscore, self.lower_span(param.pat.span))),
             _ => {
                 self.dcx().span_delayed_bug(
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index ed70d9ee91f5a..07e3b28bcf658 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -96,7 +96,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt};
 use rustc_session::lint;
-use rustc_span::{BytePos, Span, Symbol, kw, sym};
+use rustc_span::{BytePos, Span, Symbol, sym};
 use tracing::{debug, instrument};
 
 use self::LiveNodeKind::*;
@@ -1481,9 +1481,6 @@ impl<'tcx> Liveness<'_, 'tcx> {
 
     fn should_warn(&self, var: Variable) -> Option<String> {
         let name = self.ir.variable_name(var);
-        if name == kw::Empty {
-            return None;
-        }
         let name = name.as_str();
         if name.as_bytes()[0] == b'_' {
             return None;
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 533e216ddb291..117d2ccdde380 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -3999,22 +3999,17 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
             self.report_error(ident.span, error(ident));
         }
 
-        // Record as bound if it's valid:
-        let ident_valid = ident.name != kw::Empty;
-        if ident_valid {
-            bindings.last_mut().unwrap().1.insert(ident);
-        }
+        // Record as bound.
+        bindings.last_mut().unwrap().1.insert(ident);
 
         if already_bound_or {
             // `Variant1(a) | Variant2(a)`, ok
             // Reuse definition from the first `a`.
             self.innermost_rib_bindings(ValueNS)[&ident]
         } else {
+            // A completely fresh binding is added to the set.
             let res = Res::Local(pat_id);
-            if ident_valid {
-                // A completely fresh binding add to the set if it's valid.
-                self.innermost_rib_bindings(ValueNS).insert(ident, res);
-            }
+            self.innermost_rib_bindings(ValueNS).insert(ident, res);
             res
         }
     }

From 3123df8ef0cc32318d96b90620396d8b22d2ffb3 Mon Sep 17 00:00:00 2001
From: Mara Bos <m-ou.se@m-ou.se>
Date: Thu, 27 Mar 2025 18:29:58 +0100
Subject: [PATCH 04/17] Implement `super let`.

---
 compiler/rustc_ast/src/ast.rs                 |  3 +-
 compiler/rustc_ast/src/mut_visit.rs           |  3 +-
 compiler/rustc_ast/src/visit.rs               |  2 +-
 compiler/rustc_ast_lowering/src/block.rs      |  3 +-
 compiler/rustc_ast_lowering/src/lib.rs        |  1 +
 compiler/rustc_ast_pretty/src/pprust/state.rs |  3 +
 compiler/rustc_expand/src/build.rs            |  2 +
 compiler/rustc_hir/src/hir.rs                 |  4 +-
 .../rustc_hir_analysis/src/check/region.rs    | 91 +++++++++++++++----
 compiler/rustc_hir_pretty/src/lib.rs          | 10 +-
 .../rustc_hir_typeck/src/gather_locals.rs     |  2 +-
 compiler/rustc_parse/src/parser/stmt.rs       | 14 +--
 tests/ui/stats/input-stats.stderr             | 36 ++++----
 13 files changed, 126 insertions(+), 48 deletions(-)

diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 97e6879c33e99..78cc663a8e379 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1169,6 +1169,7 @@ pub enum MacStmtStyle {
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Local {
     pub id: NodeId,
+    pub super_: Option<Span>,
     pub pat: P<Pat>,
     pub ty: Option<P<Ty>>,
     pub kind: LocalKind,
@@ -3926,7 +3927,7 @@ mod size_asserts {
     static_assert_size!(Item, 144);
     static_assert_size!(ItemKind, 80);
     static_assert_size!(LitKind, 24);
-    static_assert_size!(Local, 80);
+    static_assert_size!(Local, 96);
     static_assert_size!(MetaItemLit, 40);
     static_assert_size!(Param, 40);
     static_assert_size!(Pat, 72);
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index f7d13acdfc402..58af024dc1639 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -704,7 +704,8 @@ fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut Pare
 }
 
 fn walk_local<T: MutVisitor>(vis: &mut T, local: &mut P<Local>) {
-    let Local { id, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut();
+    let Local { id, super_, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut();
+    visit_opt(super_, |sp| vis.visit_span(sp));
     vis.visit_id(id);
     visit_attrs(vis, attrs);
     vis.visit_pat(pat);
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 1ef92ff8898ef..37e32671b2948 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -323,7 +323,7 @@ pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::R
 }
 
 pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) -> V::Result {
-    let Local { id: _, pat, ty, kind, span: _, colon_sp: _, attrs, tokens: _ } = local;
+    let Local { id: _, super_: _, pat, ty, kind, span: _, colon_sp: _, attrs, tokens: _ } = local;
     walk_list!(visitor, visit_attribute, attrs);
     try_visit!(visitor.visit_pat(pat));
     visit_opt!(visitor, visit_ty, ty);
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index 1d9ca6bb9c8cb..c3222b79e55c9 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -95,6 +95,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
     fn lower_local(&mut self, l: &Local) -> &'hir hir::LetStmt<'hir> {
         // Let statements are allowed to have impl trait in bindings.
+        let super_ = l.super_;
         let ty = l.ty.as_ref().map(|t| {
             self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable))
         });
@@ -109,7 +110,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let span = self.lower_span(l.span);
         let source = hir::LocalSource::Normal;
         self.lower_attrs(hir_id, &l.attrs, l.span);
-        self.arena.alloc(hir::LetStmt { hir_id, ty, pat, init, els, span, source })
+        self.arena.alloc(hir::LetStmt { hir_id, super_, ty, pat, init, els, span, source })
     }
 
     fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index d5d6dcd8d631d..0dd8bd79604e3 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -2223,6 +2223,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             self.attrs.insert(hir_id.local_id, a);
         }
         let local = hir::LetStmt {
+            super_: None,
             hir_id,
             init,
             pat,
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 3dbfc191f8f50..e2dc334f7efca 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1336,6 +1336,9 @@ impl<'a> State<'a> {
                 self.print_outer_attributes(&loc.attrs);
                 self.space_if_not_bol();
                 self.ibox(INDENT_UNIT);
+                if loc.super_.is_some() {
+                    self.word_nbsp("let");
+                }
                 self.word_nbsp("let");
 
                 self.ibox(INDENT_UNIT);
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index f68172c1f67c0..6d616cf84bbd4 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -230,6 +230,7 @@ impl<'a> ExtCtxt<'a> {
             self.pat_ident(sp, ident)
         };
         let local = P(ast::Local {
+            super_: None,
             pat,
             ty,
             id: ast::DUMMY_NODE_ID,
@@ -245,6 +246,7 @@ impl<'a> ExtCtxt<'a> {
     /// Generates `let _: Type;`, which is usually used for type assertions.
     pub fn stmt_let_type_only(&self, span: Span, ty: P<ast::Ty>) -> ast::Stmt {
         let local = P(ast::Local {
+            super_: None,
             pat: self.pat_wild(span),
             ty: Some(ty),
             id: ast::DUMMY_NODE_ID,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 1a6c15b66a45f..14b7c31285ef7 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1817,6 +1817,8 @@ pub enum StmtKind<'hir> {
 /// Represents a `let` statement (i.e., `let <pat>:<ty> = <init>;`).
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub struct LetStmt<'hir> {
+    /// Span of `super` in `super let`.
+    pub super_: Option<Span>,
     pub pat: &'hir Pat<'hir>,
     /// Type annotation, if any (otherwise the type will be inferred).
     pub ty: Option<&'hir Ty<'hir>>,
@@ -4850,7 +4852,7 @@ mod size_asserts {
     static_assert_size!(ImplItemKind<'_>, 40);
     static_assert_size!(Item<'_>, 88);
     static_assert_size!(ItemKind<'_>, 64);
-    static_assert_size!(LetStmt<'_>, 64);
+    static_assert_size!(LetStmt<'_>, 72);
     static_assert_size!(Param<'_>, 32);
     static_assert_size!(Pat<'_>, 72);
     static_assert_size!(Path<'_>, 40);
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index cf66ab708bb9e..15d1217589184 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -8,6 +8,7 @@
 
 use std::mem;
 
+use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
@@ -44,6 +45,8 @@ struct ScopeResolutionVisitor<'tcx> {
     scope_tree: ScopeTree,
 
     cx: Context,
+
+    extended_super_lets: FxHashMap<hir::ItemLocalId, Option<Scope>>,
 }
 
 /// Records the lifetime of a local variable as `cx.var_parent`
@@ -214,18 +217,29 @@ fn resolve_stmt<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, stmt: &'tcx hi
     let stmt_id = stmt.hir_id.local_id;
     debug!("resolve_stmt(stmt.id={:?})", stmt_id);
 
-    // Every statement will clean up the temporaries created during
-    // execution of that statement. Therefore each statement has an
-    // associated destruction scope that represents the scope of the
-    // statement plus its destructors, and thus the scope for which
-    // regions referenced by the destructors need to survive.
+    if let hir::StmtKind::Let(LetStmt { super_: Some(_), .. }) = stmt.kind {
+        // `super let` statement does not start a new scope, such that
+        //
+        //     { super let x = identity(&temp()); &x }.method();
+        //
+        // behaves exactly as
+        //
+        //     (&identity(&temp()).method();
+        intravisit::walk_stmt(visitor, stmt);
+    } else {
+        // Every statement will clean up the temporaries created during
+        // execution of that statement. Therefore each statement has an
+        // associated destruction scope that represents the scope of the
+        // statement plus its destructors, and thus the scope for which
+        // regions referenced by the destructors need to survive.
 
-    let prev_parent = visitor.cx.parent;
-    visitor.enter_node_scope_with_dtor(stmt_id, true);
+        let prev_parent = visitor.cx.parent;
+        visitor.enter_node_scope_with_dtor(stmt_id, true);
 
-    intravisit::walk_stmt(visitor, stmt);
+        intravisit::walk_stmt(visitor, stmt);
 
-    visitor.cx.parent = prev_parent;
+        visitor.cx.parent = prev_parent;
+    }
 }
 
 fn resolve_expr<'tcx>(
@@ -485,10 +499,9 @@ fn resolve_local<'tcx>(
     visitor: &mut ScopeResolutionVisitor<'tcx>,
     pat: Option<&'tcx hir::Pat<'tcx>>,
     init: Option<&'tcx hir::Expr<'tcx>>,
+    super_let: bool,
 ) {
-    debug!("resolve_local(pat={:?}, init={:?})", pat, init);
-
-    let blk_scope = visitor.cx.var_parent;
+    debug!("resolve_local(pat={:?}, init={:?}, super_let={:?})", pat, init, super_let);
 
     // As an exception to the normal rules governing temporary
     // lifetimes, initializers in a let have a temporary lifetime
@@ -546,14 +559,50 @@ fn resolve_local<'tcx>(
     // A, but the inner rvalues `a()` and `b()` have an extended lifetime
     // due to rule C.
 
+    if super_let {
+        if let Some(scope) = visitor.extended_super_lets.remove(&pat.unwrap().hir_id.local_id) {
+            // This expression was lifetime-extended by a parent let binding. E.g.
+            //
+            //     let a = {
+            //         super let b = temp();
+            //         &b
+            //     };
+            //
+            // (Which needs to behave exactly as: let a = &temp();)
+            //
+            // Processing of `let a` will have already decided to extend the lifetime of this
+            // `super let` to its own var_scope. We use that scope.
+            visitor.cx.var_parent = scope;
+        } else {
+            // This `super let` is not subject to lifetime extension from a parent let binding. E.g.
+            //
+            //     identity({ super let x = temp(); &x }).method();
+            //
+            // (Which needs to behave exactly as: identity(&temp()).method();)
+            //
+            // Iterate up to the enclosing destruction scope to find the same scope that will also
+            // be used for the result of the block itself.
+            while let Some(s) = visitor.cx.var_parent {
+                let parent = visitor.scope_tree.parent_map.get(&s).cloned();
+                if let Some(Scope { data: ScopeData::Destruction, .. }) = parent {
+                    break;
+                }
+                visitor.cx.var_parent = parent;
+            }
+        }
+    }
+
     if let Some(expr) = init {
-        record_rvalue_scope_if_borrow_expr(visitor, expr, blk_scope);
+        record_rvalue_scope_if_borrow_expr(visitor, expr, visitor.cx.var_parent);
 
         if let Some(pat) = pat {
             if is_binding_pat(pat) {
                 visitor.scope_tree.record_rvalue_candidate(
                     expr.hir_id,
-                    RvalueCandidate { target: expr.hir_id.local_id, lifetime: blk_scope },
+                    RvalueCandidate {
+                        target: expr.hir_id.local_id,
+                        lifetime: visitor.cx.var_parent,
+                    },
                 );
             }
         }
@@ -565,6 +614,7 @@ fn resolve_local<'tcx>(
     if let Some(expr) = init {
         visitor.visit_expr(expr);
     }
+
     if let Some(pat) = pat {
         visitor.visit_pat(pat);
     }
@@ -642,6 +692,7 @@ fn resolve_local<'tcx>(
     ///        | [ ..., E&, ... ]
     ///        | ( ..., E&, ... )
     ///        | {...; E&}
+    ///        | { super let ... = E&; ... }
     ///        | if _ { ...; E& } else { ...; E& }
     ///        | match _ { ..., _ => E&, ... }
     ///        | box E&
@@ -678,6 +729,13 @@ fn resolve_local<'tcx>(
                 if let Some(subexpr) = block.expr {
                     record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id);
                 }
+                for stmt in block.stmts {
+                    if let hir::StmtKind::Let(local) = stmt.kind
+                        && let Some(_) = local.super_
+                    {
+                        visitor.extended_super_lets.insert(local.pat.hir_id.local_id, blk_id);
+                    }
+                }
             }
             hir::ExprKind::If(_, then_block, else_block) => {
                 record_rvalue_scope_if_borrow_expr(visitor, then_block, blk_id);
@@ -803,7 +861,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> {
                     local_id: body.value.hir_id.local_id,
                     data: ScopeData::Destruction,
                 });
-                resolve_local(this, None, Some(body.value));
+                resolve_local(this, None, Some(body.value), false);
             }
         })
     }
@@ -821,7 +879,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> {
         resolve_expr(self, ex, false);
     }
     fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) {
-        resolve_local(self, Some(l.pat), l.init)
+        resolve_local(self, Some(l.pat), l.init, l.super_.is_some());
     }
     fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
         let body = self.tcx.hir_body(c.body);
@@ -850,6 +908,7 @@ pub(crate) fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
             cx: Context { parent: None, var_parent: None },
             pessimistic_yield: false,
             fixup_scopes: vec![],
+            extended_super_lets: Default::default(),
         };
 
         visitor.scope_tree.root_body = Some(body.value.hir_id);
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 8c0c17f7a7d6a..5a3849e7afdc7 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -960,12 +960,16 @@ impl<'a> State<'a> {
 
     fn print_local(
         &mut self,
+        super_: bool,
         init: Option<&hir::Expr<'_>>,
         els: Option<&hir::Block<'_>>,
         decl: impl Fn(&mut Self),
     ) {
         self.space_if_not_bol();
         self.ibox(INDENT_UNIT);
+        if super_ {
+            self.word_nbsp("super");
+        }
         self.word_nbsp("let");
 
         self.ibox(INDENT_UNIT);
@@ -995,7 +999,9 @@ impl<'a> State<'a> {
         self.maybe_print_comment(st.span.lo());
         match st.kind {
             hir::StmtKind::Let(loc) => {
-                self.print_local(loc.init, loc.els, |this| this.print_local_decl(loc));
+                self.print_local(loc.super_.is_some(), loc.init, loc.els, |this| {
+                    this.print_local_decl(loc)
+                });
             }
             hir::StmtKind::Item(item) => self.ann.nested(self, Nested::Item(item)),
             hir::StmtKind::Expr(expr) => {
@@ -1488,7 +1494,7 @@ impl<'a> State<'a> {
 
                 // Print `let _t = $init;`:
                 let temp = Ident::from_str("_t");
-                self.print_local(Some(init), None, |this| this.print_ident(temp));
+                self.print_local(false, Some(init), None, |this| this.print_ident(temp));
                 self.word(";");
 
                 // Print `_t`:
diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs
index 48fd5f1f98249..5d87e800096fe 100644
--- a/compiler/rustc_hir_typeck/src/gather_locals.rs
+++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -43,7 +43,7 @@ pub(super) struct Declaration<'a> {
 
 impl<'a> From<&'a hir::LetStmt<'a>> for Declaration<'a> {
     fn from(local: &'a hir::LetStmt<'a>) -> Self {
-        let hir::LetStmt { hir_id, pat, ty, span, init, els, source: _ } = *local;
+        let hir::LetStmt { hir_id, super_: _, pat, ty, span, init, els, source: _ } = *local;
         Declaration { hir_id, pat, ty, span, init, origin: DeclOrigin::LocalDecl { els } }
     }
 }
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 2cd09aa8959c4..e00fd40ecee75 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -75,10 +75,11 @@ impl<'a> Parser<'a> {
 
         let stmt = if self.token.is_keyword(kw::Super) && self.is_keyword_ahead(1, &[kw::Let]) {
             self.collect_tokens(None, attrs, force_collect, |this, attrs| {
+                let super_span = this.token.span;
                 this.expect_keyword(exp!(Super))?;
-                this.psess.gated_spans.gate(sym::super_let, this.prev_token.span);
                 this.expect_keyword(exp!(Let))?;
-                let local = this.parse_local(attrs)?; // FIXME(mara): implement super let
+                this.psess.gated_spans.gate(sym::super_let, super_span);
+                let local = this.parse_local(Some(super_span), attrs)?;
                 let trailing = Trailing::from(capture_semi && this.token == token::Semi);
                 Ok((
                     this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)),
@@ -89,7 +90,7 @@ impl<'a> Parser<'a> {
         } else if self.token.is_keyword(kw::Let) {
             self.collect_tokens(None, attrs, force_collect, |this, attrs| {
                 this.expect_keyword(exp!(Let))?;
-                let local = this.parse_local(attrs)?;
+                let local = this.parse_local(None, attrs)?;
                 let trailing = Trailing::from(capture_semi && this.token == token::Semi);
                 Ok((
                     this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)),
@@ -294,7 +295,7 @@ impl<'a> Parser<'a> {
         force_collect: ForceCollect,
     ) -> PResult<'a, Stmt> {
         let stmt = self.collect_tokens(None, attrs, force_collect, |this, attrs| {
-            let local = this.parse_local(attrs)?;
+            let local = this.parse_local(None, attrs)?;
             // FIXME - maybe capture semicolon in recovery?
             Ok((
                 this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)),
@@ -308,8 +309,8 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a local variable declaration.
-    fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
-        let lo = self.prev_token.span;
+    fn parse_local(&mut self, super_: Option<Span>, attrs: AttrVec) -> PResult<'a, P<Local>> {
+        let lo = super_.unwrap_or(self.prev_token.span);
 
         if self.token.is_keyword(kw::Const) && self.look_ahead(1, |t| t.is_ident()) {
             self.dcx().emit_err(errors::ConstLetMutuallyExclusive { span: lo.to(self.token.span) });
@@ -411,6 +412,7 @@ impl<'a> Parser<'a> {
         };
         let hi = if self.token == token::Semi { self.token.span } else { self.prev_token.span };
         Ok(P(ast::Local {
+            super_,
             ty,
             pat,
             kind,
diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr
index 24e3894864787..b369af62f8760 100644
--- a/tests/ui/stats/input-stats.stderr
+++ b/tests/ui/stats/input-stats.stderr
@@ -5,25 +5,25 @@ ast-stats-1 Crate                     40 ( 0.6%)             1            40
 ast-stats-1 GenericArgs               40 ( 0.6%)             1            40
 ast-stats-1 - AngleBracketed            40 ( 0.6%)             1
 ast-stats-1 ExprField                 48 ( 0.7%)             1            48
-ast-stats-1 Attribute                 64 ( 1.0%)             2            32
+ast-stats-1 Attribute                 64 ( 0.9%)             2            32
 ast-stats-1 - DocComment                32 ( 0.5%)             1
 ast-stats-1 - Normal                    32 ( 0.5%)             1
 ast-stats-1 WherePredicate            72 ( 1.1%)             1            72
 ast-stats-1 - BoundPredicate            72 ( 1.1%)             1
 ast-stats-1 ForeignItem               80 ( 1.2%)             1            80
 ast-stats-1 - Fn                        80 ( 1.2%)             1
-ast-stats-1 Local                     80 ( 1.2%)             1            80
 ast-stats-1 Arm                       96 ( 1.4%)             2            48
+ast-stats-1 Local                     96 ( 1.4%)             1            96
 ast-stats-1 FnDecl                   120 ( 1.8%)             5            24
 ast-stats-1 Param                    160 ( 2.4%)             4            40
 ast-stats-1 Stmt                     160 ( 2.4%)             5            32
 ast-stats-1 - Let                       32 ( 0.5%)             1
 ast-stats-1 - MacCall                   32 ( 0.5%)             1
 ast-stats-1 - Expr                      96 ( 1.4%)             3
-ast-stats-1 Block                    192 ( 2.9%)             6            32
+ast-stats-1 Block                    192 ( 2.8%)             6            32
 ast-stats-1 FieldDef                 208 ( 3.1%)             2           104
 ast-stats-1 Variant                  208 ( 3.1%)             2           104
-ast-stats-1 AssocItem                320 ( 4.8%)             4            80
+ast-stats-1 AssocItem                320 ( 4.7%)             4            80
 ast-stats-1 - Fn                       160 ( 2.4%)             2
 ast-stats-1 - Type                     160 ( 2.4%)             2
 ast-stats-1 GenericBound             352 ( 5.2%)             4            88
@@ -33,7 +33,7 @@ ast-stats-1 Pat                      504 ( 7.5%)             7            72
 ast-stats-1 - Struct                    72 ( 1.1%)             1
 ast-stats-1 - Wild                      72 ( 1.1%)             1
 ast-stats-1 - Ident                    360 ( 5.3%)             5
-ast-stats-1 Expr                     576 ( 8.6%)             8            72
+ast-stats-1 Expr                     576 ( 8.5%)             8            72
 ast-stats-1 - Match                     72 ( 1.1%)             1
 ast-stats-1 - Path                      72 ( 1.1%)             1
 ast-stats-1 - Struct                    72 ( 1.1%)             1
@@ -41,8 +41,8 @@ ast-stats-1 - Lit                      144 ( 2.1%)             2
 ast-stats-1 - Block                    216 ( 3.2%)             3
 ast-stats-1 PathSegment              744 (11.0%)            31            24
 ast-stats-1 Ty                       896 (13.3%)            14            64
-ast-stats-1 - Ptr                       64 ( 1.0%)             1
-ast-stats-1 - Ref                       64 ( 1.0%)             1
+ast-stats-1 - Ptr                       64 ( 0.9%)             1
+ast-stats-1 - Ref                       64 ( 0.9%)             1
 ast-stats-1 - ImplicitSelf             128 ( 1.9%)             2
 ast-stats-1 - Path                     640 ( 9.5%)            10
 ast-stats-1 Item                   1_296 (19.2%)             9           144
@@ -53,7 +53,7 @@ ast-stats-1 - Trait                    144 ( 2.1%)             1
 ast-stats-1 - Fn                       288 ( 4.3%)             2
 ast-stats-1 - Use                      432 ( 6.4%)             3
 ast-stats-1 ----------------------------------------------------------------
-ast-stats-1 Total                  6_736                   116
+ast-stats-1 Total                  6_752                   116
 ast-stats-1
 ast-stats-2 POST EXPANSION AST STATS
 ast-stats-2 Name                Accumulated Size         Count     Item Size
@@ -66,8 +66,8 @@ ast-stats-2 WherePredicate            72 ( 1.0%)             1            72
 ast-stats-2 - BoundPredicate            72 ( 1.0%)             1
 ast-stats-2 ForeignItem               80 ( 1.1%)             1            80
 ast-stats-2 - Fn                        80 ( 1.1%)             1
-ast-stats-2 Local                     80 ( 1.1%)             1            80
 ast-stats-2 Arm                       96 ( 1.3%)             2            48
+ast-stats-2 Local                     96 ( 1.3%)             1            96
 ast-stats-2 FnDecl                   120 ( 1.6%)             5            24
 ast-stats-2 InlineAsm                120 ( 1.6%)             1           120
 ast-stats-2 Attribute                128 ( 1.7%)             4            32
@@ -84,14 +84,14 @@ ast-stats-2 Variant                  208 ( 2.8%)             2           104
 ast-stats-2 AssocItem                320 ( 4.3%)             4            80
 ast-stats-2 - Fn                       160 ( 2.2%)             2
 ast-stats-2 - Type                     160 ( 2.2%)             2
-ast-stats-2 GenericBound             352 ( 4.8%)             4            88
-ast-stats-2 - Trait                    352 ( 4.8%)             4
+ast-stats-2 GenericBound             352 ( 4.7%)             4            88
+ast-stats-2 - Trait                    352 ( 4.7%)             4
 ast-stats-2 GenericParam             480 ( 6.5%)             5            96
 ast-stats-2 Pat                      504 ( 6.8%)             7            72
 ast-stats-2 - Struct                    72 ( 1.0%)             1
 ast-stats-2 - Wild                      72 ( 1.0%)             1
 ast-stats-2 - Ident                    360 ( 4.9%)             5
-ast-stats-2 Expr                     648 ( 8.8%)             9            72
+ast-stats-2 Expr                     648 ( 8.7%)             9            72
 ast-stats-2 - InlineAsm                 72 ( 1.0%)             1
 ast-stats-2 - Match                     72 ( 1.0%)             1
 ast-stats-2 - Path                      72 ( 1.0%)             1
@@ -113,7 +113,7 @@ ast-stats-2 - Trait                    144 ( 1.9%)             1
 ast-stats-2 - Fn                       288 ( 3.9%)             2
 ast-stats-2 - Use                      576 ( 7.8%)             4
 ast-stats-2 ----------------------------------------------------------------
-ast-stats-2 Total                  7_400                   127
+ast-stats-2 Total                  7_416                   127
 ast-stats-2
 hir-stats HIR STATS
 hir-stats Name                Accumulated Size         Count     Item Size
@@ -126,11 +126,11 @@ hir-stats TraitItemRef              56 ( 0.6%)             2            28
 hir-stats GenericArg                64 ( 0.7%)             4            16
 hir-stats - Type                      16 ( 0.2%)             1
 hir-stats - Lifetime                  48 ( 0.5%)             3
-hir-stats Local                     64 ( 0.7%)             1            64
 hir-stats Param                     64 ( 0.7%)             2            32
 hir-stats Body                      72 ( 0.8%)             3            24
 hir-stats ImplItemRef               72 ( 0.8%)             2            36
 hir-stats InlineAsm                 72 ( 0.8%)             1            72
+hir-stats Local                     72 ( 0.8%)             1            72
 hir-stats WherePredicate            72 ( 0.8%)             3            24
 hir-stats - BoundPredicate            72 ( 0.8%)             3
 hir-stats Arm                       80 ( 0.9%)             2            40
@@ -143,8 +143,8 @@ hir-stats Attribute                128 ( 1.4%)             4            32
 hir-stats FieldDef                 128 ( 1.4%)             2            64
 hir-stats GenericArgs              144 ( 1.6%)             3            48
 hir-stats Variant                  144 ( 1.6%)             2            72
-hir-stats GenericBound             256 ( 2.9%)             4            64
-hir-stats - Trait                    256 ( 2.9%)             4
+hir-stats GenericBound             256 ( 2.8%)             4            64
+hir-stats - Trait                    256 ( 2.8%)             4
 hir-stats Block                    288 ( 3.2%)             6            48
 hir-stats Pat                      360 ( 4.0%)             5            72
 hir-stats - Struct                    72 ( 0.8%)             1
@@ -156,7 +156,7 @@ hir-stats Ty                       720 ( 8.0%)            15            48
 hir-stats - Ptr                       48 ( 0.5%)             1
 hir-stats - Ref                       48 ( 0.5%)             1
 hir-stats - Path                     624 ( 6.9%)            13
-hir-stats Expr                     768 ( 8.6%)            12            64
+hir-stats Expr                     768 ( 8.5%)            12            64
 hir-stats - InlineAsm                 64 ( 0.7%)             1
 hir-stats - Match                     64 ( 0.7%)             1
 hir-stats - Path                      64 ( 0.7%)             1
@@ -174,5 +174,5 @@ hir-stats - Use                      352 ( 3.9%)             4
 hir-stats Path                   1_240 (13.8%)            31            40
 hir-stats PathSegment            1_920 (21.4%)            40            48
 hir-stats ----------------------------------------------------------------
-hir-stats Total                  8_980                   180
+hir-stats Total                  8_988                   180
 hir-stats

From f02e2786397f9954ad019ba2af7f574c1e17c904 Mon Sep 17 00:00:00 2001
From: Mara Bos <m-ou.se@m-ou.se>
Date: Wed, 2 Apr 2025 23:48:13 +0200
Subject: [PATCH 05/17] Fix typo in pretty printing super let.

Co-authored-by: lcnr <rust@lcnr.de>
---
 compiler/rustc_ast_pretty/src/pprust/state.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index e2dc334f7efca..5e0bfc210e4bd 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1337,7 +1337,7 @@ impl<'a> State<'a> {
                 self.space_if_not_bol();
                 self.ibox(INDENT_UNIT);
                 if loc.super_.is_some() {
-                    self.word_nbsp("let");
+                    self.word_nbsp("super");
                 }
                 self.word_nbsp("let");
 

From 3e6cc7689d467fce677faed22672b592363b0f5f Mon Sep 17 00:00:00 2001
From: Mara Bos <m-ou.se@m-ou.se>
Date: Wed, 2 Apr 2025 23:55:41 +0200
Subject: [PATCH 06/17] Boolean hate.

---
 .../rustc_hir_analysis/src/check/region.rs    | 20 ++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 15d1217589184..fedca3302f9bf 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -495,13 +495,19 @@ fn resolve_expr<'tcx>(
     visitor.cx = prev_cx;
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+enum LetKind {
+    Regular,
+    Super,
+}
+
 fn resolve_local<'tcx>(
     visitor: &mut ScopeResolutionVisitor<'tcx>,
     pat: Option<&'tcx hir::Pat<'tcx>>,
     init: Option<&'tcx hir::Expr<'tcx>>,
-    super_let: bool,
+    let_kind: LetKind,
 ) {
-    debug!("resolve_local(pat={:?}, init={:?}, super_let={:?})", pat, init, super_let);
+    debug!("resolve_local(pat={:?}, init={:?}, let_kind={:?})", pat, init, let_kind);
 
     // As an exception to the normal rules governing temporary
     // lifetimes, initializers in a let have a temporary lifetime
@@ -559,7 +565,7 @@ fn resolve_local<'tcx>(
     // A, but the inner rvalues `a()` and `b()` have an extended lifetime
     // due to rule C.
 
-    if super_let {
+    if let_kind == LetKind::Super {
         if let Some(scope) = visitor.extended_super_lets.remove(&pat.unwrap().hir_id.local_id) {
             // This expression was lifetime-extended by a parent let binding. E.g.
             //
@@ -861,7 +867,7 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> {
                     local_id: body.value.hir_id.local_id,
                     data: ScopeData::Destruction,
                 });
-                resolve_local(this, None, Some(body.value), false);
+                resolve_local(this, None, Some(body.value), LetKind::Regular);
             }
         })
     }
@@ -879,7 +885,11 @@ impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> {
         resolve_expr(self, ex, false);
     }
     fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) {
-        resolve_local(self, Some(l.pat), l.init, l.super_.is_some());
+        let let_kind = match l.super_ {
+            Some(_) => LetKind::Super,
+            None => LetKind::Regular,
+        };
+        resolve_local(self, Some(l.pat), l.init, let_kind);
     }
     fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
         let body = self.tcx.hir_body(c.body);

From b9babad9277fbf0b6209a3075e01f7b2dd043bf4 Mon Sep 17 00:00:00 2001
From: Mara Bos <m-ou.se@m-ou.se>
Date: Fri, 4 Apr 2025 09:38:04 +0200
Subject: [PATCH 07/17] Add feature gate test for cfg'd out super let.

---
 tests/ui/feature-gates/feature-gate-super-let.rs     |  7 +++++++
 tests/ui/feature-gates/feature-gate-super-let.stderr | 12 +++++++++++-
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/tests/ui/feature-gates/feature-gate-super-let.rs b/tests/ui/feature-gates/feature-gate-super-let.rs
index cfe92a42669d1..7be0800391338 100644
--- a/tests/ui/feature-gates/feature-gate-super-let.rs
+++ b/tests/ui/feature-gates/feature-gate-super-let.rs
@@ -2,3 +2,10 @@ fn main() {
     super let a = 1;
     //~^ ERROR `super let` is experimental
 }
+
+// Check that it also isn't accepted in cfg'd out code.
+#[cfg(any())]
+fn a() {
+    super let a = 1;
+    //~^ ERROR `super let` is experimental
+}
diff --git a/tests/ui/feature-gates/feature-gate-super-let.stderr b/tests/ui/feature-gates/feature-gate-super-let.stderr
index a64e1b374f9c0..4d088594f6df5 100644
--- a/tests/ui/feature-gates/feature-gate-super-let.stderr
+++ b/tests/ui/feature-gates/feature-gate-super-let.stderr
@@ -8,6 +8,16 @@ LL |     super let a = 1;
    = help: add `#![feature(super_let)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: aborting due to 1 previous error
+error[E0658]: `super let` is experimental
+  --> $DIR/feature-gate-super-let.rs:9:5
+   |
+LL |     super let a = 1;
+   |     ^^^^^
+   |
+   = note: see issue #139076 <https://github.com/rust-lang/rust/issues/139076> for more information
+   = help: add `#![feature(super_let)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0658`.

From 6c3417dd15cb560a860ddea063193c68b5b47b87 Mon Sep 17 00:00:00 2001
From: Mara Bos <m-ou.se@m-ou.se>
Date: Fri, 4 Apr 2025 11:16:32 +0200
Subject: [PATCH 08/17] fixup! Implement `super let`.

---
 compiler/rustc_feature/src/unstable.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 710e129b609fe..7647f8e4b2360 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -630,7 +630,7 @@ declare_features! (
     /// Allows string patterns to dereference values to match them.
     (unstable, string_deref_patterns, "1.67.0", Some(87121)),
     /// Allows `super let` statements.
-    (incomplete, super_let, "CURRENT_RUSTC_VERSION", Some(139076)),
+    (unstable, super_let, "CURRENT_RUSTC_VERSION", Some(139076)),
     /// Allows subtrait items to shadow supertrait items.
     (unstable, supertrait_item_shadowing, "1.86.0", Some(89151)),
     /// Allows using `#[thread_local]` on `static` items.

From 0522ed059db967db26143387747b46c11528f49b Mon Sep 17 00:00:00 2001
From: Bryanskiy <ivakin.kir@gmail.com>
Date: Fri, 4 Apr 2025 15:32:00 +0300
Subject: [PATCH 09/17] Default auto traits: fix perf

---
 .../src/collect/predicates_of.rs              | 30 +---------
 .../src/hir_ty_lowering/bounds.rs             | 56 ++++++++++++++++---
 2 files changed, 51 insertions(+), 35 deletions(-)

diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 776b23bea8e11..320225a7a663a 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -172,33 +172,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     };
 
     if let Node::TraitItem(item) = node {
-        let parent = tcx.local_parent(item.hir_id().owner.def_id);
-        let Node::Item(parent_trait) = tcx.hir_node_by_def_id(parent) else {
-            unreachable!();
-        };
-
-        let (trait_generics, trait_bounds) = match parent_trait.kind {
-            hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => (generics, supertraits),
-            hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits),
-            _ => unreachable!(),
-        };
-
-        // Implicitly add `Self: DefaultAutoTrait` clauses on trait associated items if
-        // they are not added as super trait bounds to the trait itself. See comment on
-        // `requires_default_supertraits` for more details.
-        if !icx.lowerer().requires_default_supertraits(trait_bounds, trait_generics) {
-            let mut bounds = Vec::new();
-            let self_ty_where_predicates = (parent, item.generics.predicates);
-            icx.lowerer().add_default_traits_with_filter(
-                &mut bounds,
-                tcx.types.self_param,
-                &[],
-                Some(self_ty_where_predicates),
-                item.span,
-                |tr| tr != hir::LangItem::Sized,
-            );
-            predicates.extend(bounds);
-        }
+        let mut bounds = Vec::new();
+        icx.lowerer().add_default_trait_item_bounds(item, &mut bounds);
+        predicates.extend(bounds);
     }
 
     let generics = tcx.generics_of(def_id);
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index c3bb860538ee8..55087d1f400f5 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -43,12 +43,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     }
 
     /// Checks whether `Self: DefaultAutoTrait` bounds should be added on trait super bounds
-    /// or associative items.
+    /// or associated items.
     ///
     /// To keep backward compatibility with existing code, `experimental_default_bounds` bounds
     /// should be added everywhere, including super bounds. However this causes a huge performance
     /// costs. For optimization purposes instead of adding default supertraits, bounds
-    /// are added to the associative items:
+    /// are added to the associated items:
     ///
     /// ```ignore(illustrative)
     /// // Default bounds are generated in the following way:
@@ -81,7 +81,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     ///
     /// Therefore, `experimental_default_bounds` are still being added to supertraits if
     /// the `SelfTyParam` or `AssocItemConstraint` were found in a trait header.
-    pub(crate) fn requires_default_supertraits(
+    fn requires_default_supertraits(
         &self,
         hir_bounds: &'tcx [hir::GenericBound<'tcx>],
         hir_generics: &'tcx hir::Generics<'tcx>,
@@ -120,6 +120,43 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         found
     }
 
+    /// Implicitly add `Self: DefaultAutoTrait` clauses on trait associated items if
+    /// they are not added as super trait bounds to the trait itself. See
+    /// `requires_default_supertraits` for more information.
+    pub(crate) fn add_default_trait_item_bounds(
+        &self,
+        trait_item: &hir::TraitItem<'tcx>,
+        bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
+    ) {
+        let tcx = self.tcx();
+        if !tcx.sess.opts.unstable_opts.experimental_default_bounds {
+            return;
+        }
+
+        let parent = tcx.local_parent(trait_item.hir_id().owner.def_id);
+        let hir::Node::Item(parent_trait) = tcx.hir_node_by_def_id(parent) else {
+            unreachable!();
+        };
+
+        let (trait_generics, trait_bounds) = match parent_trait.kind {
+            hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => (generics, supertraits),
+            hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits),
+            _ => unreachable!(),
+        };
+
+        if !self.requires_default_supertraits(trait_bounds, trait_generics) {
+            let self_ty_where_predicates = (parent, trait_item.generics.predicates);
+            self.add_default_traits_with_filter(
+                bounds,
+                tcx.types.self_param,
+                &[],
+                Some(self_ty_where_predicates),
+                trait_item.span,
+                |tr| tr != hir::LangItem::Sized,
+            );
+        }
+    }
+
     /// Lazily sets `experimental_default_bounds` to true on trait super bounds.
     /// See `requires_default_supertraits` for more information.
     pub(crate) fn add_default_super_traits(
@@ -130,6 +167,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         hir_generics: &'tcx hir::Generics<'tcx>,
         span: Span,
     ) {
+        if !self.tcx().sess.opts.unstable_opts.experimental_default_bounds {
+            return;
+        }
+
         assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias));
         if self.requires_default_supertraits(hir_bounds, hir_generics) {
             let self_ty_where_predicates = (trait_def_id, hir_generics.predicates);
@@ -263,11 +304,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 seen_unbound = true;
             }
             let emit_relax_err = || {
-                let unbound_traits =
-                    match self.tcx().sess.opts.unstable_opts.experimental_default_bounds {
-                        true => "`?Sized` and `experimental_default_bounds`",
-                        false => "`?Sized`",
-                    };
+                let unbound_traits = match tcx.sess.opts.unstable_opts.experimental_default_bounds {
+                    true => "`?Sized` and `experimental_default_bounds`",
+                    false => "`?Sized`",
+                };
                 // There was a `?Trait` bound, but it was neither `?Sized` nor `experimental_default_bounds`.
                 tcx.dcx().span_err(
                     unbound.span,

From ccbef74fc5a6bf5adfdd79fd15601fe91aa22c66 Mon Sep 17 00:00:00 2001
From: Mara Bos <m-ou.se@m-ou.se>
Date: Fri, 4 Apr 2025 11:16:37 +0200
Subject: [PATCH 10/17] Add tests for super let.

---
 tests/ui/super-let.borrowck.stderr | 174 ++++++++++++++++++
 tests/ui/super-let.rs              | 286 +++++++++++++++++++++++++++++
 2 files changed, 460 insertions(+)
 create mode 100644 tests/ui/super-let.borrowck.stderr
 create mode 100644 tests/ui/super-let.rs

diff --git a/tests/ui/super-let.borrowck.stderr b/tests/ui/super-let.borrowck.stderr
new file mode 100644
index 0000000000000..01ef29d875880
--- /dev/null
+++ b/tests/ui/super-let.borrowck.stderr
@@ -0,0 +1,174 @@
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/super-let.rs:30:28
+   |
+LL |             super let b = DropMe(&mut x);
+   |                                  ------ `x` is borrowed here
+...
+LL |         #[cfg(borrowck)] { x = true; }
+   |                            ^^^^^^^^ `x` is assigned to here but it was already borrowed
+...
+LL |     }
+   |     - borrow might be used here, when `b` is dropped and runs the `Drop` code for type `DropMe`
+
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/super-let.rs:46:28
+   |
+LL |             super let b = &DropMe(&mut x);
+   |                            --------------
+   |                            |      |
+   |                            |      `x` is borrowed here
+   |                            a temporary with access to the borrow is created here ...
+...
+LL |         #[cfg(borrowck)] { x = true; }
+   |                            ^^^^^^^^ `x` is assigned to here but it was already borrowed
+...
+LL |     }
+   |     - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DropMe`
+
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/super-let.rs:64:32
+   |
+LL |             super let b = identity(&DropMe(&mut x));
+   |                                     --------------
+   |                                     |      |
+   |                                     |      `x` is borrowed here
+   |                                     a temporary with access to the borrow is created here ...
+LL |             #[cfg(borrowck)] { x = true; }
+   |                                ^^^^^^^^ `x` is assigned to here but it was already borrowed
+...
+LL |         };
+   |          - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DropMe`
+
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/super-let.rs:87:36
+   |
+LL |                 super let b = identity(&DropMe(&mut x));
+   |                                         --------------
+   |                                         |      |
+   |                                         |      `x` is borrowed here
+   |                                         a temporary with access to the borrow is created here ...
+...
+LL |                 #[cfg(borrowck)] { x = true; }
+   |                                    ^^^^^^^^ `x` is assigned to here but it was already borrowed
+...
+LL |         ));
+   |           - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DropMe`
+
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/super-let.rs:107:28
+   |
+LL |                 super let b = DropMe(&mut x);
+   |                                      ------ `x` is borrowed here
+...
+LL |         #[cfg(borrowck)] { x = true; }
+   |                            ^^^^^^^^ `x` is assigned to here but it was already borrowed
+...
+LL |     }
+   |     - borrow might be used here, when `b` is dropped and runs the `Drop` code for type `DropMe`
+
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/super-let.rs:125:28
+   |
+LL |             super let b = DropMe(&mut x);
+   |                                  ------ `x` is borrowed here
+...
+LL |         #[cfg(borrowck)] { x = true; }
+   |                            ^^^^^^^^ `x` is assigned to here but it was already borrowed
+...
+LL |     }
+   |     - borrow might be used here, when `b` is dropped and runs the `Drop` code for type `DropMe`
+
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/super-let.rs:143:28
+   |
+LL |             super let b = DropMe(&mut x);
+   |                                  ------ `x` is borrowed here
+...
+LL |         #[cfg(borrowck)] { x = true; }
+   |                            ^^^^^^^^ `x` is assigned to here but it was already borrowed
+...
+LL |     }
+   |     - borrow might be used here, when `b` is dropped and runs the `Drop` code for type `DropMe`
+
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/super-let.rs:159:28
+   |
+LL |             b = DropMe(&mut x);
+   |                        ------ `x` is borrowed here
+...
+LL |         #[cfg(borrowck)] { x = true; }
+   |                            ^^^^^^^^ `x` is assigned to here but it was already borrowed
+LL |         drop(a);
+   |              - borrow later used here
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/super-let.rs:172:33
+   |
+LL |         #[cfg(borrowck)] { a = &String::from("asdf"); };
+   |                                 ^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
+   |                                 |
+   |                                 creates a temporary value which is freed while still in use
+...
+LL |         let _ = a;
+   |                 - borrow later used here
+   |
+   = note: consider using a `let` binding to create a longer lived value
+
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/super-let.rs:206:28
+   |
+LL |                     super let d = &DropMe(&mut x);
+   |                                    --------------
+   |                                    |      |
+   |                                    |      `x` is borrowed here
+   |                                    a temporary with access to the borrow is created here ...
+...
+LL |         #[cfg(borrowck)] { x = true; }
+   |                            ^^^^^^^^ `x` is assigned to here but it was already borrowed
+...
+LL |     }
+   |     - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DropMe`
+
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/super-let.rs:227:32
+   |
+LL |                     super let d = identity(&DropMe(&mut x));
+   |                                             --------------
+   |                                             |      |
+   |                                             |      `x` is borrowed here
+   |                                             a temporary with access to the borrow is created here ...
+...
+LL |             #[cfg(borrowck)] { x = true; }
+   |                                ^^^^^^^^ `x` is assigned to here but it was already borrowed
+...
+LL |         };
+   |          - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DropMe`
+
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/super-let.rs:246:28
+   |
+LL |             super let b = DropMe(&mut x);
+   |                                  ------ `x` is borrowed here
+...
+LL |         #[cfg(borrowck)] { x = true; }
+   |                            ^^^^^^^^ `x` is assigned to here but it was already borrowed
+...
+LL |     }
+   |     - borrow might be used here, when `b` is dropped and runs the `Drop` code for type `DropMe`
+
+error[E0506]: cannot assign to `x` because it is borrowed
+  --> $DIR/super-let.rs:263:28
+   |
+LL |             let dropme = Some(DropMe(&mut x));
+   |                                      ------ `x` is borrowed here
+...
+LL |         #[cfg(borrowck)] { x = true; }
+   |                            ^^^^^^^^ `x` is assigned to here but it was already borrowed
+...
+LL |     }
+   |     - borrow might be used here, when `x` is dropped and runs the `Drop` code for type `DropMe`
+
+error: aborting due to 13 previous errors
+
+Some errors have detailed explanations: E0506, E0716.
+For more information about an error, try `rustc --explain E0506`.
diff --git a/tests/ui/super-let.rs b/tests/ui/super-let.rs
new file mode 100644
index 0000000000000..380470f792fe1
--- /dev/null
+++ b/tests/ui/super-let.rs
@@ -0,0 +1,286 @@
+// Check in two ways:
+// - borrowck: Check with borrow checking errors when things are alive and dead.
+// - runtime: Check with a mutable bool if things are dropped on time.
+//
+//@ revisions: runtime borrowck
+//@ [runtime] run-pass
+//@ [borrowck] check-fail
+
+#![allow(dropping_references)]
+#![feature(super_let, stmt_expr_attributes)]
+
+use std::convert::identity;
+
+struct DropMe<'a>(&'a mut bool);
+
+impl Drop for DropMe<'_> {
+    fn drop(&mut self) {
+        *self.0 = true;
+    }
+}
+
+// Check that a super let variable lives as long as the result of a block.
+fn extended_variable() {
+    let mut x = false;
+    {
+        let a = {
+            super let b = DropMe(&mut x);
+            &b
+        };
+        #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
+        drop(a);
+        // DropMe is still alive here...
+    }
+    // ... but not here.
+    assert_eq!(x, true) // ok
+}
+
+// Check that the init expression of a super let is subject to (temporary) lifetime extension.
+fn extended_temporary() {
+    let mut x = false;
+    {
+        let a = {
+            super let b = &DropMe(&mut x);
+            b
+        };
+        #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
+        drop(a);
+        // DropMe is still alive here...
+    }
+    // ... but not here.
+    assert_eq!(x, true); // ok
+}
+
+// Check that even non-extended temporaries live until the end of the block,
+// but (unlike extended temporaries) not beyond that.
+//
+// This is necessary for things like select(pin!(identity(&temp()))) to work.
+fn non_extended() {
+    let mut x = false;
+    {
+        let _a = {
+            // Use identity() to supress temporary lifetime extension.
+            super let b = identity(&DropMe(&mut x));
+            #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
+            b
+            // DropMe is still alive here...
+        };
+        // ... but not here.
+        assert_eq!(x, true); // ok
+    }
+}
+
+// Check that even non-extended temporaries live until the end of the block,
+// but (unlike extended temporaries) not beyond that.
+//
+// This is necessary for things like select(pin!(identity(&temp()))) to work.
+fn non_extended_in_expression() {
+    let mut x = false;
+    {
+        identity((
+            {
+                // Use identity() to supress temporary lifetime extension.
+                super let b = identity(&DropMe(&mut x));
+                b
+            },
+            {
+                #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
+                // DropMe is still alive here...
+            }
+        ));
+        // ... but not here.
+        assert_eq!(x, true); // ok
+    }
+}
+
+// Check `super let` in a match arm.
+fn match_arm() {
+    let mut x = false;
+    {
+        let a = match Some(123) {
+            Some(_) => {
+                super let b = DropMe(&mut x);
+                &b
+            }
+            None => unreachable!(),
+        };
+        #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
+        drop(a);
+        // DropMe is still alive here...
+    }
+    // ... but not here.
+    assert_eq!(x, true); // ok
+}
+
+// Check `super let` in an if body.
+fn if_body() {
+    let mut x = false;
+    {
+        let a = if true {
+            super let b = DropMe(&mut x);
+            &b
+        } else {
+            unreachable!()
+        };
+        #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
+        drop(a);
+        // DropMe is still alive here...
+    }
+    // ... but not here.
+    assert_eq!(x, true); // ok
+}
+
+// Check `super let` in an else body.
+fn else_body() {
+    let mut x = false;
+    {
+        let a = if false {
+            unreachable!()
+        } else {
+            super let b = DropMe(&mut x);
+            &b
+        };
+        #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
+        drop(a);
+        // DropMe is still alive here...
+    }
+    // ... but not here.
+    assert_eq!(x, true); // ok
+}
+
+fn without_initializer() {
+    let mut x = false;
+    {
+        let a = {
+            super let b;
+            b = DropMe(&mut x);
+            b
+        };
+        #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
+        drop(a);
+        // DropMe is still alive here...
+    }
+    // ... but not here.
+    assert_eq!(x, true);
+}
+
+// Assignment isn't special, even when assigning to a `super let` variable.
+fn assignment() {
+    let mut x = false;
+    {
+        super let a;
+        #[cfg(borrowck)] { a = &String::from("asdf"); }; //[borrowck]~ ERROR dropped while borrowed
+        #[cfg(runtime)] { a = drop(&DropMe(&mut x)); } // Temporary dropped at the `;` as usual.
+        assert_eq!(x, true);
+        let _ = a;
+    }
+}
+
+// `super let mut` should work just fine.
+fn mutable() {
+    let mut x = false;
+    {
+        let a = {
+            super let mut b = None;
+            &mut b
+        };
+        *a = Some(DropMe(&mut x));
+    }
+    assert_eq!(x, true);
+}
+
+// Temporary lifetime extension should recurse through `super let`s.
+fn multiple_levels() {
+    let mut x = false;
+    {
+        let a = {
+            super let b = {
+                super let c = {
+                    super let d = &DropMe(&mut x);
+                    d
+                };
+                c
+            };
+            b
+        };
+        #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
+        drop(a);
+        // DropMe is still alive here...
+    }
+    // ... but not here.
+    assert_eq!(x, true);
+}
+
+// Non-extended temporaries should be dropped at the
+// end of the first parent statement that isn't `super`.
+fn multiple_levels_but_no_extension() {
+    let mut x = false;
+    {
+        let _a = {
+            super let b = {
+                super let c = {
+                    super let d = identity(&DropMe(&mut x));
+                    d
+                };
+                c
+            };
+            #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
+            b
+            // DropMe is still alive here...
+        };
+        // ... but not here.
+        assert_eq!(x, true);
+    }
+}
+
+// Check for potential weird interactions with `let else`.
+fn super_let_and_let_else() {
+    let mut x = false;
+    {
+        let a = 'a: {
+            let Some(_) = Some(123) else { unreachable!() };
+            super let b = DropMe(&mut x);
+            let None = Some(123) else { break 'a &b };
+            unreachable!()
+        };
+        #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
+        // DropMe is still alive here...
+        drop(a);
+    }
+    // ... but not here.
+    assert_eq!(x, true);
+}
+
+// Check if `super let .. else ..;` works.
+fn super_let_else() {
+    let mut x = false;
+    {
+        let a = {
+            let dropme = Some(DropMe(&mut x));
+            super let Some(x) = dropme else { unreachable!() };
+            &x
+        };
+        #[cfg(borrowck)] { x = true; } //[borrowck]~ ERROR borrowed
+        // DropMe is still alive here...
+        drop(a);
+    }
+    // ... but not here.
+    assert_eq!(x, true);
+}
+
+fn main() {
+    extended_variable();
+    extended_temporary();
+    non_extended();
+    non_extended_in_expression();
+    match_arm();
+    if_body();
+    else_body();
+    without_initializer();
+    assignment();
+    mutable();
+    multiple_levels();
+    multiple_levels_but_no_extension();
+    super_let_and_let_else();
+    super_let_else();
+}

From 5eb535c568de730a36bbf96f0ec1163942301b15 Mon Sep 17 00:00:00 2001
From: Skgland <3877590+Skgland@users.noreply.github.com>
Date: Sun, 6 Apr 2025 21:32:58 +0200
Subject: [PATCH 11/17] remove compiler support for `extern "rust-intrinsic"`
 blocks

---
 compiler/rustc_abi/src/extern_abi.rs          |   4 +-
 compiler/rustc_ast_lowering/src/stability.rs  |   4 -
 .../rustc_hir_analysis/src/check/check.rs     | 108 ++++++++----------
 .../rustc_hir_analysis/src/check/intrinsic.rs |   2 +-
 compiler/rustc_hir_analysis/src/check/mod.rs  |   9 --
 compiler/rustc_hir_analysis/src/collect.rs    |   8 +-
 compiler/rustc_hir_typeck/src/check.rs        |   4 +-
 compiler/rustc_hir_typeck/src/coercion.rs     |   5 -
 compiler/rustc_metadata/src/native_libs.rs    |   2 +-
 compiler/rustc_middle/src/ty/instance.rs      |   2 +-
 compiler/rustc_middle/src/ty/layout.rs        |   4 +-
 compiler/rustc_middle/src/ty/util.rs          |   7 +-
 compiler/rustc_passes/src/check_attr.rs       |   2 +-
 .../rustc_smir/src/rustc_internal/internal.rs |   1 -
 .../rustc_smir/src/rustc_smir/convert/ty.rs   |   1 -
 compiler/rustc_smir/src/stable_mir/ty.rs      |   1 -
 .../rustc_target/src/callconv/loongarch.rs    |  10 +-
 compiler/rustc_target/src/callconv/mod.rs     |  13 +--
 compiler/rustc_target/src/callconv/riscv.rs   |  10 +-
 compiler/rustc_target/src/callconv/x86.rs     |  11 +-
 compiler/rustc_target/src/spec/mod.rs         |  11 +-
 compiler/rustc_ty_utils/src/abi.rs            |   4 +-
 src/librustdoc/clean/types.rs                 |   3 -
 23 files changed, 79 insertions(+), 147 deletions(-)

diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs
index 4d70afd4e0bca..55f4845d21670 100644
--- a/compiler/rustc_abi/src/extern_abi.rs
+++ b/compiler/rustc_abi/src/extern_abi.rs
@@ -60,7 +60,6 @@ pub enum ExternAbi {
     System {
         unwind: bool,
     },
-    RustIntrinsic,
     RustCall,
     /// *Not* a stable ABI, just directly use the Rust types to describe the ABI for LLVM. Even
     /// normally ABI-compatible Rust types can become ABI-incompatible with this ABI!
@@ -128,7 +127,6 @@ abi_impls! {
             RiscvInterruptS =><= "riscv-interrupt-s",
             RustCall =><= "rust-call",
             RustCold =><= "rust-cold",
-            RustIntrinsic =><= "rust-intrinsic",
             Stdcall { unwind: false } =><= "stdcall",
             Stdcall { unwind: true } =><= "stdcall-unwind",
             System { unwind: false } =><= "system",
@@ -199,7 +197,7 @@ impl ExternAbi {
     /// - are subject to change between compiler versions
     pub fn is_rustic_abi(self) -> bool {
         use ExternAbi::*;
-        matches!(self, Rust | RustCall | RustIntrinsic | RustCold)
+        matches!(self, Rust | RustCall | RustCold)
     }
 
     pub fn supports_varargs(self) -> bool {
diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs
index a2004bbb39f09..eb052ba1c6d78 100644
--- a/compiler/rustc_ast_lowering/src/stability.rs
+++ b/compiler/rustc_ast_lowering/src/stability.rs
@@ -79,10 +79,6 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
         | ExternAbi::SysV64 { .. }
         | ExternAbi::System { .. }
         | ExternAbi::EfiApi => Ok(()),
-        // implementation details
-        ExternAbi::RustIntrinsic => {
-            Err(UnstableAbi { abi, feature: sym::intrinsics, explain: GateReason::ImplDetail })
-        }
         ExternAbi::Unadjusted => {
             Err(UnstableAbi { abi, feature: sym::abi_unadjusted, explain: GateReason::ImplDetail })
         }
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index a079865676304..e3ed20e1b318d 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -741,10 +741,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 
             for &assoc_item in assoc_items.in_definition_order() {
                 match assoc_item.kind {
-                    ty::AssocKind::Fn => {
-                        let abi = tcx.fn_sig(assoc_item.def_id).skip_binder().abi();
-                        forbid_intrinsic_abi(tcx, assoc_item.ident(tcx).span, abi);
-                    }
                     ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => {
                         let trait_args = GenericArgs::identity_for_item(tcx, def_id);
                         let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
@@ -788,65 +784,59 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             };
             check_abi(tcx, it.span, abi);
 
-            match abi {
-                ExternAbi::RustIntrinsic => {
-                    for item in items {
-                        intrinsic::check_intrinsic_type(
-                            tcx,
-                            item.id.owner_id.def_id,
-                            item.span,
-                            item.ident.name,
-                            abi,
-                        );
-                    }
+            for item in items {
+                let def_id = item.id.owner_id.def_id;
+
+                if tcx.has_attr(def_id, sym::rustc_intrinsic) {
+                    intrinsic::check_intrinsic_type(
+                        tcx,
+                        item.id.owner_id.def_id,
+                        item.span,
+                        item.ident.name,
+                        abi,
+                    );
                 }
 
-                _ => {
-                    for item in items {
-                        let def_id = item.id.owner_id.def_id;
-                        let generics = tcx.generics_of(def_id);
-                        let own_counts = generics.own_counts();
-                        if generics.own_params.len() - own_counts.lifetimes != 0 {
-                            let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts)
-                            {
-                                (_, 0) => ("type", "types", Some("u32")),
-                                // We don't specify an example value, because we can't generate
-                                // a valid value for any type.
-                                (0, _) => ("const", "consts", None),
-                                _ => ("type or const", "types or consts", None),
-                            };
-                            struct_span_code_err!(
-                                tcx.dcx(),
-                                item.span,
-                                E0044,
-                                "foreign items may not have {kinds} parameters",
-                            )
-                            .with_span_label(item.span, format!("can't have {kinds} parameters"))
-                            .with_help(
-                                // FIXME: once we start storing spans for type arguments, turn this
-                                // into a suggestion.
-                                format!(
-                                    "replace the {} parameters with concrete {}{}",
-                                    kinds,
-                                    kinds_pl,
-                                    egs.map(|egs| format!(" like `{egs}`")).unwrap_or_default(),
-                                ),
-                            )
-                            .emit();
-                        }
+                let generics = tcx.generics_of(def_id);
+                let own_counts = generics.own_counts();
+                if generics.own_params.len() - own_counts.lifetimes != 0 {
+                    let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) {
+                        (_, 0) => ("type", "types", Some("u32")),
+                        // We don't specify an example value, because we can't generate
+                        // a valid value for any type.
+                        (0, _) => ("const", "consts", None),
+                        _ => ("type or const", "types or consts", None),
+                    };
+                    struct_span_code_err!(
+                        tcx.dcx(),
+                        item.span,
+                        E0044,
+                        "foreign items may not have {kinds} parameters",
+                    )
+                    .with_span_label(item.span, format!("can't have {kinds} parameters"))
+                    .with_help(
+                        // FIXME: once we start storing spans for type arguments, turn this
+                        // into a suggestion.
+                        format!(
+                            "replace the {} parameters with concrete {}{}",
+                            kinds,
+                            kinds_pl,
+                            egs.map(|egs| format!(" like `{egs}`")).unwrap_or_default(),
+                        ),
+                    )
+                    .emit();
+                }
 
-                        let item = tcx.hir_foreign_item(item.id);
-                        match &item.kind {
-                            hir::ForeignItemKind::Fn(sig, _, _) => {
-                                require_c_abi_if_c_variadic(tcx, sig.decl, abi, item.span);
-                            }
-                            hir::ForeignItemKind::Static(..) => {
-                                check_static_inhabited(tcx, def_id);
-                                check_static_linkage(tcx, def_id);
-                            }
-                            _ => {}
-                        }
+                let item = tcx.hir_foreign_item(item.id);
+                match &item.kind {
+                    hir::ForeignItemKind::Fn(sig, _, _) => {
+                        require_c_abi_if_c_variadic(tcx, sig.decl, abi, item.span);
+                    }
+                    hir::ForeignItemKind::Static(..) => {
+                        check_static_inhabited(tcx, def_id);
+                        check_static_linkage(tcx, def_id);
                     }
+                    _ => {}
                 }
             }
         }
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 42d785c8dd0fe..0bf9e127989f0 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -1,4 +1,4 @@
-//! Type-checking for the rust-intrinsic intrinsics that the compiler exposes.
+//! Type-checking for the `#[rustc_intrinsic]` intrinsics that the compiler exposes.
 
 use rustc_abi::ExternAbi;
 use rustc_errors::codes::*;
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 7c5d7b33a34d3..30921b6f055d5 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -137,15 +137,6 @@ fn get_owner_return_paths(
     })
 }
 
-/// Forbid defining intrinsics in Rust code,
-/// as they must always be defined by the compiler.
-// FIXME: Move this to a more appropriate place.
-pub fn forbid_intrinsic_abi(tcx: TyCtxt<'_>, sp: Span, abi: ExternAbi) {
-    if let ExternAbi::RustIntrinsic = abi {
-        tcx.dcx().span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
-    }
-}
-
 pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
     // Only restricted on wasm target for now
     if !tcx.sess.target.is_like_wasm {
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 625f51dd29eac..e9cd22435d958 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -42,7 +42,6 @@ use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::ObligationCtxt;
 use tracing::{debug, instrument};
 
-use crate::check::intrinsic::intrinsic_operation_unsafety;
 use crate::errors;
 use crate::hir_ty_lowering::errors::assoc_kind_str;
 use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
@@ -1704,18 +1703,13 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
     abi: ExternAbi,
     safety: hir::Safety,
 ) -> ty::PolyFnSig<'tcx> {
-    let safety = if abi == ExternAbi::RustIntrinsic {
-        intrinsic_operation_unsafety(tcx, def_id)
-    } else {
-        safety
-    };
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
     let fty =
         ItemCtxt::new(tcx, def_id).lowerer().lower_fn_ty(hir_id, safety, abi, decl, None, None);
 
     // Feature gate SIMD types in FFI, since I am not sure that the
     // ABIs are handled at all correctly. -huonw
-    if abi != ExternAbi::RustIntrinsic && !tcx.features().simd_ffi() {
+    if !tcx.features().simd_ffi() {
         let check = |hir_ty: &hir::Ty<'_>, ty: Ty<'_>| {
             if ty.is_simd() {
                 let snip = tcx
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index dabae7b1d094c..2189fdf0f3439 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -5,7 +5,7 @@ use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir_analysis::check::{check_function_signature, forbid_intrinsic_abi};
+use rustc_hir_analysis::check::check_function_signature;
 use rustc_infer::infer::RegionVariableOrigin;
 use rustc_infer::traits::WellFormedLoc;
 use rustc_middle::ty::{self, Binder, Ty, TyCtxt};
@@ -50,8 +50,6 @@ pub(super) fn check_fn<'a, 'tcx>(
 
     let span = body.value.span;
 
-    forbid_intrinsic_abi(tcx, span, fn_sig.abi);
-
     GatherLocalsVisitor::new(fcx).visit_body(body);
 
     // C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index f42ca3af2b35c..f1571cf4c8317 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -37,7 +37,6 @@
 
 use std::ops::Deref;
 
-use rustc_abi::ExternAbi;
 use rustc_attr_parsing::InlineAttr;
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, Diag, struct_span_code_err};
@@ -1240,10 +1239,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         };
         if let (Some(a_sig), Some(b_sig)) = (a_sig, b_sig) {
-            // Intrinsics are not coercible to function pointers.
-            if a_sig.abi() == ExternAbi::RustIntrinsic || b_sig.abi() == ExternAbi::RustIntrinsic {
-                return Err(TypeError::IntrinsicCast);
-            }
             // The signature must match.
             let (a_sig, b_sig) = self.normalize(new.span, (a_sig, b_sig));
             let sig = self
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 130a425e9c74a..cfb0de8475c8f 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -207,7 +207,7 @@ impl<'tcx> Collector<'tcx> {
 
         let sess = self.tcx.sess;
 
-        if matches!(abi, ExternAbi::Rust | ExternAbi::RustIntrinsic) {
+        if matches!(abi, ExternAbi::Rust) {
             return;
         }
 
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 55ebd15248c61..07f2a602f2bf2 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -71,7 +71,7 @@ pub enum InstanceKind<'tcx> {
     /// - coroutines
     Item(DefId),
 
-    /// An intrinsic `fn` item (with `"rust-intrinsic"` ABI).
+    /// An intrinsic `fn` item (with`#[rustc_instrinsic]`).
     ///
     /// Alongside `Virtual`, this is the only `InstanceKind` that does not have its own callable MIR.
     /// Instead, codegen and const eval "magically" evaluate calls to intrinsics purely in the
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index ebb6a8c08a54c..7ebfebea44e56 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1265,9 +1265,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi)
         | CCmseNonSecureCall
         | CCmseNonSecureEntry
         | Unadjusted => false,
-        Rust | RustCall | RustCold | RustIntrinsic => {
-            tcx.sess.panic_strategy() == PanicStrategy::Unwind
-        }
+        Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index e4863896fc8b3..857b462b9eb1e 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -2,7 +2,7 @@
 
 use std::{fmt, iter};
 
-use rustc_abi::{ExternAbi, Float, Integer, IntegerType, Size};
+use rustc_abi::{Float, Integer, IntegerType, Size};
 use rustc_apfloat::Float as _;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -1719,10 +1719,7 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 /// the compiler to make some assumptions about its shape; if the user doesn't use a feature gate, they may
 /// cause an ICE that we otherwise may want to prevent.
 pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::IntrinsicDef> {
-    if tcx.features().intrinsics()
-        && (matches!(tcx.fn_sig(def_id).skip_binder().abi(), ExternAbi::RustIntrinsic)
-            || tcx.has_attr(def_id, sym::rustc_intrinsic))
-    {
+    if tcx.features().intrinsics() && tcx.has_attr(def_id, sym::rustc_intrinsic) {
         let must_be_overridden = match tcx.hir_node_by_def_id(def_id) {
             hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { has_body, .. }, .. }) => {
                 !has_body
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 669349f3380aa..9161b23428a00 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -1598,7 +1598,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         if target == Target::ForeignMod
             && let hir::Node::Item(item) = self.tcx.hir_node(hir_id)
             && let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item
-            && !matches!(abi, ExternAbi::Rust | ExternAbi::RustIntrinsic)
+            && !matches!(abi, ExternAbi::Rust)
         {
             return;
         }
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index 36b68cc139826..6e13b87c41d73 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -491,7 +491,6 @@ impl RustcInternal for Abi {
             Abi::CCmseNonSecureCall => rustc_abi::ExternAbi::CCmseNonSecureCall,
             Abi::CCmseNonSecureEntry => rustc_abi::ExternAbi::CCmseNonSecureEntry,
             Abi::System { unwind } => rustc_abi::ExternAbi::System { unwind },
-            Abi::RustIntrinsic => rustc_abi::ExternAbi::RustIntrinsic,
             Abi::RustCall => rustc_abi::ExternAbi::RustCall,
             Abi::Unadjusted => rustc_abi::ExternAbi::Unadjusted,
             Abi::RustCold => rustc_abi::ExternAbi::RustCold,
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index 1ba25aa0e971a..28fc68d5e491b 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -871,7 +871,6 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi {
             ExternAbi::CCmseNonSecureCall => Abi::CCmseNonSecureCall,
             ExternAbi::CCmseNonSecureEntry => Abi::CCmseNonSecureEntry,
             ExternAbi::System { unwind } => Abi::System { unwind },
-            ExternAbi::RustIntrinsic => Abi::RustIntrinsic,
             ExternAbi::RustCall => Abi::RustCall,
             ExternAbi::Unadjusted => Abi::Unadjusted,
             ExternAbi::RustCold => Abi::RustCold,
diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs
index 1efa2fe13c565..3fcbbb0e138be 100644
--- a/compiler/rustc_smir/src/stable_mir/ty.rs
+++ b/compiler/rustc_smir/src/stable_mir/ty.rs
@@ -1093,7 +1093,6 @@ pub enum Abi {
     CCmseNonSecureCall,
     CCmseNonSecureEntry,
     System { unwind: bool },
-    RustIntrinsic,
     RustCall,
     Unadjusted,
     RustCold,
diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs
index 209d7483e612a..c779720f97b9c 100644
--- a/compiler/rustc_target/src/callconv/loongarch.rs
+++ b/compiler/rustc_target/src/callconv/loongarch.rs
@@ -1,6 +1,6 @@
 use rustc_abi::{
-    BackendRepr, ExternAbi, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size,
-    TyAbiInterface, TyAndLayout, Variants,
+    BackendRepr, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size, TyAbiInterface,
+    TyAndLayout, Variants,
 };
 
 use crate::callconv::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Uniform};
@@ -364,15 +364,11 @@ where
     }
 }
 
-pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: ExternAbi)
+pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
     C: HasDataLayout + HasTargetSpec,
 {
-    if abi == ExternAbi::RustIntrinsic {
-        return;
-    }
-
     let grlen = cx.data_layout().pointer_size.bits();
 
     for arg in fn_abi.args.iter_mut() {
diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs
index 55e39d093e233..7ecc46cc69db9 100644
--- a/compiler/rustc_target/src/callconv/mod.rs
+++ b/compiler/rustc_target/src/callconv/mod.rs
@@ -717,16 +717,16 @@ impl<'a, Ty> FnAbi<'a, Ty> {
         }
     }
 
-    pub fn adjust_for_rust_abi<C>(&mut self, cx: &C, abi: ExternAbi)
+    pub fn adjust_for_rust_abi<C>(&mut self, cx: &C)
     where
         Ty: TyAbiInterface<'a, C> + Copy,
         C: HasDataLayout + HasTargetSpec,
     {
         let spec = cx.target_spec();
         match &*spec.arch {
-            "x86" => x86::compute_rust_abi_info(cx, self, abi),
-            "riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self, abi),
-            "loongarch64" => loongarch::compute_rust_abi_info(cx, self, abi),
+            "x86" => x86::compute_rust_abi_info(cx, self),
+            "riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self),
+            "loongarch64" => loongarch::compute_rust_abi_info(cx, self),
             "aarch64" => aarch64::compute_rust_abi_info(cx, self),
             _ => {}
         };
@@ -850,10 +850,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
                     //
                     // Note that the intrinsic ABI is exempt here as those are not
                     // real functions anyway, and the backend expects very specific types.
-                    if abi != ExternAbi::RustIntrinsic
-                        && spec.simd_types_indirect
-                        && !can_pass_simd_directly(arg)
-                    {
+                    if spec.simd_types_indirect && !can_pass_simd_directly(arg) {
                         arg.make_indirect();
                     }
                 }
diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs
index 7368e225efa74..cd1d3cd1eee05 100644
--- a/compiler/rustc_target/src/callconv/riscv.rs
+++ b/compiler/rustc_target/src/callconv/riscv.rs
@@ -5,8 +5,8 @@
 // https://github.com/llvm/llvm-project/blob/8e780252a7284be45cf1ba224cabd884847e8e92/clang/lib/CodeGen/TargetInfo.cpp#L9311-L9773
 
 use rustc_abi::{
-    BackendRepr, ExternAbi, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size,
-    TyAbiInterface, TyAndLayout, Variants,
+    BackendRepr, FieldsShape, HasDataLayout, Primitive, Reg, RegKind, Size, TyAbiInterface,
+    TyAndLayout, Variants,
 };
 
 use crate::callconv::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Uniform};
@@ -370,15 +370,11 @@ where
     }
 }
 
-pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: ExternAbi)
+pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
     C: HasDataLayout + HasTargetSpec,
 {
-    if abi == ExternAbi::RustIntrinsic {
-        return;
-    }
-
     let xlen = cx.data_layout().pointer_size.bits();
 
     for arg in fn_abi.args.iter_mut() {
diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs
index ba3c140621129..8328f818f9b8f 100644
--- a/compiler/rustc_target/src/callconv/x86.rs
+++ b/compiler/rustc_target/src/callconv/x86.rs
@@ -1,6 +1,6 @@
 use rustc_abi::{
-    AddressSpace, Align, BackendRepr, ExternAbi, HasDataLayout, Primitive, Reg, RegKind,
-    TyAbiInterface, TyAndLayout,
+    AddressSpace, Align, BackendRepr, HasDataLayout, Primitive, Reg, RegKind, TyAbiInterface,
+    TyAndLayout,
 };
 
 use crate::callconv::{ArgAttribute, FnAbi, PassMode};
@@ -193,7 +193,7 @@ pub(crate) fn fill_inregs<'a, Ty, C>(
     }
 }
 
-pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: ExternAbi)
+pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
     C: HasDataLayout + HasTargetSpec,
@@ -201,10 +201,7 @@ where
     // Avoid returning floats in x87 registers on x86 as loading and storing from x87
     // registers will quiet signalling NaNs. Also avoid using SSE registers since they
     // are not always available (depending on target features).
-    if !fn_abi.ret.is_ignore()
-        // Intrinsics themselves are not "real" functions, so theres no need to change their ABIs.
-        && abi != ExternAbi::RustIntrinsic
-    {
+    if !fn_abi.ret.is_ignore() {
         let has_float = match fn_abi.ret.layout.backend_repr {
             BackendRepr::Scalar(s) => matches!(s.primitive(), Primitive::Float(_)),
             BackendRepr::ScalarPair(s1, s2) => {
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 79f73ef28b36f..64171fcc7ab34 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -2962,14 +2962,9 @@ impl Target {
     pub fn is_abi_supported(&self, abi: ExternAbi) -> bool {
         use ExternAbi::*;
         match abi {
-            Rust
-            | C { .. }
-            | System { .. }
-            | RustIntrinsic
-            | RustCall
-            | Unadjusted
-            | Cdecl { .. }
-            | RustCold => true,
+            Rust | C { .. } | System { .. } | RustCall | Unadjusted | Cdecl { .. } | RustCold => {
+                true
+            }
             EfiApi => {
                 ["arm", "aarch64", "riscv32", "riscv64", "x86", "x86_64"].contains(&&self.arch[..])
             }
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 48d5a4a0fcb0d..3d4ab33240af2 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -244,7 +244,7 @@ fn fn_sig_for_fn_abi<'tcx>(
 fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: ExternAbi, c_variadic: bool) -> Conv {
     use rustc_abi::ExternAbi::*;
     match tcx.sess.target.adjust_abi(abi, c_variadic) {
-        RustIntrinsic | Rust | RustCall => Conv::Rust,
+        Rust | RustCall => Conv::Rust,
 
         // This is intentionally not using `Conv::Cold`, as that has to preserve
         // even SIMD registers, which is generally not a good trade-off.
@@ -660,7 +660,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
     let tcx = cx.tcx();
 
     if abi.is_rustic_abi() {
-        fn_abi.adjust_for_rust_abi(cx, abi);
+        fn_abi.adjust_for_rust_abi(cx);
 
         // Look up the deduced parameter attributes for this function, if we have its def ID and
         // we're optimizing in non-incremental mode. We'll tag its parameters with those attributes
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index d3ddb77c0b33c..06e75fe1764e0 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -11,7 +11,6 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{BodyId, Mutability};
-use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety;
 use rustc_index::IndexVec;
 use rustc_metadata::rendered_const;
 use rustc_middle::span_bug;
@@ -687,8 +686,6 @@ impl Item {
                 hir::FnHeader {
                     safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
                         hir::HeaderSafety::SafeTargetFeatures
-                    } else if abi == ExternAbi::RustIntrinsic {
-                        intrinsic_operation_unsafety(tcx, def_id.expect_local()).into()
                     } else {
                         safety.into()
                     },

From 51b51b51d7931da85280382a81c4dd80c73ca754 Mon Sep 17 00:00:00 2001
From: Skgland <3877590+Skgland@users.noreply.github.com>
Date: Sun, 6 Apr 2025 21:34:00 +0200
Subject: [PATCH 12/17] remove rust-analyser  support for `extern
 "rust-intrinsic"` blocks

---
 .../rust-analyzer/crates/hir-ty/src/lib.rs    |  3 ---
 .../crates/hir-ty/src/mir/eval/shim.rs        | 14 +---------
 .../rust-analyzer/crates/hir-ty/src/utils.rs  | 26 +++++--------------
 .../src/completions/extern_abi.rs             |  1 -
 .../crates/intern/src/symbol/symbols.rs       |  1 -
 5 files changed, 7 insertions(+), 38 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index cc02b71f05c19..e4c50f2ebdb44 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -400,7 +400,6 @@ pub enum FnAbi {
     Rust,
     RustCall,
     RustCold,
-    RustIntrinsic,
     Stdcall,
     StdcallUnwind,
     System,
@@ -457,7 +456,6 @@ impl FnAbi {
             s if *s == sym::riscv_dash_interrupt_dash_s => FnAbi::RiscvInterruptS,
             s if *s == sym::rust_dash_call => FnAbi::RustCall,
             s if *s == sym::rust_dash_cold => FnAbi::RustCold,
-            s if *s == sym::rust_dash_intrinsic => FnAbi::RustIntrinsic,
             s if *s == sym::Rust => FnAbi::Rust,
             s if *s == sym::stdcall_dash_unwind => FnAbi::StdcallUnwind,
             s if *s == sym::stdcall => FnAbi::Stdcall,
@@ -500,7 +498,6 @@ impl FnAbi {
             FnAbi::Rust => "Rust",
             FnAbi::RustCall => "rust-call",
             FnAbi::RustCold => "rust-cold",
-            FnAbi::RustIntrinsic => "rust-intrinsic",
             FnAbi::Stdcall => "stdcall",
             FnAbi::StdcallUnwind => "stdcall-unwind",
             FnAbi::System => "system",
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index f61ecabb7e41d..06ac5b1ffad90 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -59,19 +59,7 @@ impl Evaluator<'_> {
 
         let function_data = self.db.function_data(def);
         let attrs = self.db.attrs(def.into());
-        let is_intrinsic = attrs.by_key(&sym::rustc_intrinsic).exists()
-            // Keep this around for a bit until extern "rustc-intrinsic" abis are no longer used
-            || (match &function_data.abi {
-                Some(abi) => *abi == sym::rust_dash_intrinsic,
-                None => match def.lookup(self.db.upcast()).container {
-                    hir_def::ItemContainerId::ExternBlockId(block) => {
-                        let id = block.lookup(self.db.upcast()).id;
-                        id.item_tree(self.db.upcast())[id.value].abi.as_ref()
-                            == Some(&sym::rust_dash_intrinsic)
-                    }
-                    _ => false,
-                },
-            });
+        let is_intrinsic = attrs.by_key(&sym::rustc_intrinsic).exists();
 
         if is_intrinsic {
             return self.exec_intrinsic(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
index 89d89fe2230af..0cfd36d9166b8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
@@ -18,7 +18,6 @@ use hir_def::{
     TypeOrConstParamId,
 };
 use hir_expand::name::Name;
-use intern::sym;
 use rustc_abi::TargetDataLayout;
 use rustc_hash::FxHashSet;
 use smallvec::{smallvec, SmallVec};
@@ -303,26 +302,13 @@ pub fn is_fn_unsafe_to_call(
 
     let loc = func.lookup(db.upcast());
     match loc.container {
-        hir_def::ItemContainerId::ExternBlockId(block) => {
-            let id = block.lookup(db.upcast()).id;
-            let is_intrinsic_block =
-                id.item_tree(db.upcast())[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic);
-            if is_intrinsic_block {
-                // legacy intrinsics
-                // extern "rust-intrinsic" intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
-                if db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists() {
-                    Unsafety::Safe
-                } else {
-                    Unsafety::Unsafe
-                }
+        hir_def::ItemContainerId::ExternBlockId(_block) => {
+            // Function in an `extern` block are always unsafe to call, except when
+            // it is marked as `safe`.
+            if data.is_safe() {
+                Unsafety::Safe
             } else {
-                // Function in an `extern` block are always unsafe to call, except when
-                // it is marked as `safe`.
-                if data.is_safe() {
-                    Unsafety::Safe
-                } else {
-                    Unsafety::Unsafe
-                }
+                Unsafety::Unsafe
             }
         }
         _ => Unsafety::Safe,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs
index 7c2cc2a6c1d8f..a3554114f4c36 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs
@@ -36,7 +36,6 @@ const SUPPORTED_CALLING_CONVENTIONS: &[&str] = &[
     "wasm",
     "system",
     "system-unwind",
-    "rust-intrinsic",
     "rust-call",
     "unadjusted",
 ];
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
index 6b77c72cee897..d4f334289f034 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -125,7 +125,6 @@ define_symbols! {
     riscv_dash_interrupt_dash_s = "riscv-interrupt-s",
     rust_dash_call = "rust-call",
     rust_dash_cold = "rust-cold",
-    rust_dash_intrinsic = "rust-intrinsic",
     stdcall_dash_unwind = "stdcall-unwind",
     system_dash_unwind = "system-unwind",
     sysv64_dash_unwind = "sysv64-unwind",

From 6dfb29624cf2fd1b6d2f31e6321bcef5e4a4a84e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= <bb-github@t-online.de>
Date: Sun, 6 Apr 2025 15:10:23 +0200
Subject: [PATCH 13/17] update docs

- src\doc\nomicon\src\ffi.md should also have its ABI list updated
---
 .../src/intrinsics/mod.rs                     |  3 +-
 compiler/rustc_feature/src/unstable.rs        |  2 +-
 library/core/src/intrinsics/mod.rs            |  1 +
 .../src/language-features/intrinsics.md       | 30 ++-----------------
 .../crates/ide/src/hover/tests.rs             | 28 ++---------------
 5 files changed, 7 insertions(+), 57 deletions(-)

diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 75f3a3c19724f..d3f47ad726334 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -1,5 +1,4 @@
-//! Codegen of intrinsics. This includes `extern "rust-intrinsic"`,
-//! functions marked with the `#[rustc_intrinsic]` attribute
+//! Codegen of intrinsics. This includes functions marked with the `#[rustc_intrinsic]` attribute
 //! and LLVM intrinsics that have symbol names starting with `llvm.`.
 
 macro_rules! intrinsic_args {
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 710e129b609fe..77d8965602ccb 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -211,7 +211,7 @@ declare_features! (
     (internal, custom_mir, "1.65.0", None),
     /// Outputs useful `assert!` messages
     (unstable, generic_assert, "1.63.0", None),
-    /// Allows using the `rust-intrinsic`'s "ABI".
+    /// Allows using the #[rustc_intrinsic] attribute.
     (internal, intrinsics, "1.0.0", None),
     /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
     (internal, lang_items, "1.0.0", None),
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index afd6192d7c473..7fa57df9928c3 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -8,6 +8,7 @@
 //! Note: any changes to the constness of intrinsics should be discussed with the language team.
 //! This includes changes in the stability of the constness.
 //!
+//! //FIXME(#132735) "old" style intrinsics support has been removed
 //! In order to make an intrinsic usable at compile-time, it needs to be declared in the "new"
 //! style, i.e. as a `#[rustc_intrinsic]` function, not inside an `extern` block. Then copy the
 //! implementation from <https://github.com/rust-lang/miri/blob/master/src/intrinsics> to
diff --git a/src/doc/unstable-book/src/language-features/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md
index 975b400447eb8..a0e38f340f581 100644
--- a/src/doc/unstable-book/src/language-features/intrinsics.md
+++ b/src/doc/unstable-book/src/language-features/intrinsics.md
@@ -52,9 +52,8 @@ with any regular function.
 Various intrinsics have native MIR operations that they correspond to. Instead of requiring
 backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass
 will convert the calls to the MIR operation. Backends do not need to know about these intrinsics
-at all. These intrinsics only make sense without a body, and can either be declared as a "rust-intrinsic"
-or as a `#[rustc_intrinsic]`. The body is never used, as calls to the intrinsic do not exist
-anymore after MIR analyses.
+at all. These intrinsics only make sense without a body, and can be declared as a `#[rustc_intrinsic]`.
+The body is never used, as calls to the intrinsic do not exist anymore after MIR analyses.
 
 ## Intrinsics without fallback logic
 
@@ -70,28 +69,3 @@ These are written without a body:
 #[rustc_intrinsic]
 pub fn abort() -> !;
 ```
-
-### Legacy extern ABI based intrinsics
-
-*This style is deprecated, always prefer the above form.*
-
-These are imported as if they were FFI functions, with the special
-`rust-intrinsic` ABI. For example, if one was in a freestanding
-context, but wished to be able to `transmute` between types, and
-perform efficient pointer arithmetic, one would import those functions
-via a declaration like
-
-```rust
-#![feature(intrinsics)]
-#![allow(internal_features)]
-# fn main() {}
-
-extern "rust-intrinsic" {
-    fn transmute<T, U>(x: T) -> U;
-
-    fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
-}
-```
-
-As with any other FFI functions, these are by default always `unsafe` to call.
-You can add `#[rustc_safe_intrinsic]` to the intrinsic to make it safe to call.
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 6b470d921f7a7..5dfd826d7f966 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -6945,9 +6945,8 @@ fn hover_feature() {
             Various intrinsics have native MIR operations that they correspond to. Instead of requiring
             backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass
             will convert the calls to the MIR operation. Backends do not need to know about these intrinsics
-            at all. These intrinsics only make sense without a body, and can either be declared as a "rust-intrinsic"
-            or as a `#[rustc_intrinsic]`. The body is never used, as calls to the intrinsic do not exist
-            anymore after MIR analyses.
+            at all. These intrinsics only make sense without a body, and can be as a `#[rustc_intrinsic]`. 
+            The body is never used, as calls to the intrinsic do not exist anymore after MIR analyses.
 
             ## Intrinsics without fallback logic
 
@@ -6960,29 +6959,6 @@ fn hover_feature() {
             `#[rustc_intrinsic_must_be_overridden]` to the function to ensure that backends don't
             invoke the body.
 
-            ### Legacy extern ABI based intrinsics
-
-            These are imported as if they were FFI functions, with the special
-            `rust-intrinsic` ABI. For example, if one was in a freestanding
-            context, but wished to be able to `transmute` between types, and
-            perform efficient pointer arithmetic, one would import those functions
-            via a declaration like
-
-            ```rust
-            #![feature(intrinsics)]
-            #![allow(internal_features)]
-            # fn main() {}
-
-            extern "rust-intrinsic" {
-                fn transmute<T, U>(x: T) -> U;
-
-                fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
-            }
-            ```
-
-            As with any other FFI functions, these are by default always `unsafe` to call.
-            You can add `#[rustc_safe_intrinsic]` to the intrinsic to make it safe to call.
-
         "#]],
     )
 }

From 7dd57f085cab4cc671b01d6dd27977c76d04de28 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bennet=20Ble=C3=9Fmann?= <bb-github@t-online.de>
Date: Sun, 6 Apr 2025 15:12:24 +0200
Subject: [PATCH 14/17] update/bless tests

---
 .../src/error_codes/E0622.md                  |  10 +-
 tests/assembly/simd-bitmask.rs                |   5 +-
 tests/assembly/simd-intrinsic-gather.rs       |   5 +-
 tests/assembly/simd-intrinsic-mask-load.rs    |   5 +-
 tests/assembly/simd-intrinsic-mask-reduce.rs  |   8 +-
 tests/assembly/simd-intrinsic-mask-store.rs   |   5 +-
 tests/assembly/simd-intrinsic-scatter.rs      |   5 +-
 tests/assembly/simd-intrinsic-select.rs       |   5 +-
 tests/codegen/avr/avr-func-addrspace.rs       |   5 +-
 .../codegen/emscripten-catch-unwind-js-eh.rs  |  13 +-
 .../emscripten-catch-unwind-wasm-eh.rs        |  14 +-
 tests/codegen/intrinsic-no-unnamed-attr.rs    |   6 +-
 tests/codegen/intrinsics/nontemporal.rs       |   5 +-
 tests/mir-opt/lower_intrinsics.rs             |   9 +-
 .../atomic-lock-free/atomic_lock_free.rs      |   5 +-
 .../avr-rjmp-offset/avr-rjmp-offsets.rs       |   7 +-
 ...abi-typo-unstable.feature_disabled.stderr} |   8 +-
 .../abi-typo-unstable.feature_enabled.stderr  |  16 +
 tests/ui/abi/abi-typo-unstable.rs             |  11 +-
 ...sociated-types-in-ambiguous-context.stderr |  36 +-
 ...ice-mutability-error-slicing-121807.stderr |  12 +-
 .../trait-impl-argument-difference-ice.stderr |  12 +-
 tests/ui/delegation/ice-issue-124347.rs       |   1 -
 tests/ui/delegation/ice-issue-124347.stderr   |  12 +-
 ...-fn-inputs-and-outputs-issue-125139.stderr | 320 +++++++++---------
 tests/ui/error-codes/E0092.rs                 |   9 +-
 tests/ui/error-codes/E0092.stderr             |   6 +-
 tests/ui/error-codes/E0093.rs                 |  11 +-
 tests/ui/error-codes/E0093.stderr             |   6 +-
 tests/ui/error-codes/E0622.rs                 |  14 +-
 tests/ui/error-codes/E0622.stderr             |   6 +-
 tests/ui/extern/extern-with-type-bounds.rs    |  21 --
 .../ui/extern/extern-with-type-bounds.stderr  |   9 -
 tests/ui/feature-gates/feature-gate-abi.rs    |  21 --
 .../ui/feature-gates/feature-gate-abi.stderr  | 172 +---------
 .../feature-gates/feature-gate-intrinsics.rs  |   9 +-
 .../feature-gate-intrinsics.stderr            |  36 +-
 .../feature-gated-feature-in-macro-arg.rs     |   6 +-
 .../feature-gated-feature-in-macro-arg.stderr |  10 +-
 tests/ui/intrinsics/always-extern.rs          |  17 -
 tests/ui/intrinsics/always-extern.stderr      |  34 --
 .../ui/intrinsics/auxiliary/cci_intrinsic.rs  |   9 +-
 .../incorrect-read_via_copy-defn.rs           |   7 +-
 .../incorrect-read_via_copy-defn.stderr       |  21 +-
 tests/ui/intrinsics/incorrect-transmute.rs    |   7 +-
 .../ui/intrinsics/incorrect-transmute.stderr  |  21 +-
 tests/ui/intrinsics/intrinsic-atomics.rs      |  74 ++--
 .../intrinsics/invalid-ABI-rust-intrinsic.rs  |  19 ++
 .../invalid-ABI-rust-intrinsic.stderr         |  35 ++
 tests/ui/intrinsics/issue-28575.rs            |   1 +
 tests/ui/intrinsics/issue-28575.stderr        |  15 +-
 .../ui/intrinsics/safe-intrinsic-mismatch.rs  |  11 +-
 .../intrinsics/safe-intrinsic-mismatch.stderr |  21 +-
 tests/ui/lint/internal_features.rs            |   5 +-
 tests/ui/print-calling-conventions.stdout     |   1 -
 ...it-should-use-self-2021-without-dyn.stderr |  56 +--
 tests/ui/suggestions/issue-116434-2015.stderr |  26 +-
 .../typeck_type_placeholder_item.stderr       |  24 +-
 ...ir-wf-check-anon-const-issue-122199.stderr |  12 +-
 59 files changed, 550 insertions(+), 742 deletions(-)
 rename tests/ui/abi/{abi-typo-unstable.stderr => abi-typo-unstable.feature_disabled.stderr} (55%)
 create mode 100644 tests/ui/abi/abi-typo-unstable.feature_enabled.stderr
 delete mode 100644 tests/ui/extern/extern-with-type-bounds.rs
 delete mode 100644 tests/ui/extern/extern-with-type-bounds.stderr
 delete mode 100644 tests/ui/intrinsics/always-extern.rs
 delete mode 100644 tests/ui/intrinsics/always-extern.stderr
 create mode 100644 tests/ui/intrinsics/invalid-ABI-rust-intrinsic.rs
 create mode 100644 tests/ui/intrinsics/invalid-ABI-rust-intrinsic.stderr

diff --git a/compiler/rustc_error_codes/src/error_codes/E0622.md b/compiler/rustc_error_codes/src/error_codes/E0622.md
index 4cb605b636d2e..e6ff949d3e9f9 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0622.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0622.md
@@ -6,8 +6,9 @@ Erroneous code example:
 #![feature(intrinsics)]
 #![allow(internal_features)]
 
-extern "rust-intrinsic" {
-    pub static atomic_singlethreadfence_seqcst: fn();
+extern "C" {
+    #[rustc_intrinsic]
+    pub static atomic_singlethreadfence_seqcst: unsafe fn();
     // error: intrinsic must be a function
 }
 
@@ -22,9 +23,8 @@ error, just declare a function. Example:
 #![feature(intrinsics)]
 #![allow(internal_features)]
 
-extern "rust-intrinsic" {
-    pub fn atomic_singlethreadfence_seqcst(); // ok!
-}
+#[rustc_intrinsic]
+pub unsafe fn atomic_singlethreadfence_seqcst(); // ok!
 
 fn main() { unsafe { atomic_singlethreadfence_seqcst(); } }
 ```
diff --git a/tests/assembly/simd-bitmask.rs b/tests/assembly/simd-bitmask.rs
index a632791153b2e..e412246108700 100644
--- a/tests/assembly/simd-bitmask.rs
+++ b/tests/assembly/simd-bitmask.rs
@@ -35,9 +35,8 @@ pub struct m64x2([i64; 2]);
 #[repr(simd)]
 pub struct m64x4([i64; 4]);
 
-extern "rust-intrinsic" {
-    fn simd_bitmask<V, B>(mask: V) -> B;
-}
+#[rustc_intrinsic]
+unsafe fn simd_bitmask<V, B>(mask: V) -> B;
 
 // CHECK-LABEL: bitmask_m8x16
 #[no_mangle]
diff --git a/tests/assembly/simd-intrinsic-gather.rs b/tests/assembly/simd-intrinsic-gather.rs
index 8c17a58046d8b..bcab0ba1cc09b 100644
--- a/tests/assembly/simd-intrinsic-gather.rs
+++ b/tests/assembly/simd-intrinsic-gather.rs
@@ -22,9 +22,8 @@ pub struct m64x4([i64; 4]);
 #[repr(simd)]
 pub struct pf64x4([*const f64; 4]);
 
-extern "rust-intrinsic" {
-    fn simd_gather<V, M, P>(values: V, mask: M, pointer: P) -> V;
-}
+#[rustc_intrinsic]
+unsafe fn simd_gather<V, M, P>(values: V, mask: M, pointer: P) -> V;
 
 // CHECK-LABEL: gather_f64x4
 #[no_mangle]
diff --git a/tests/assembly/simd-intrinsic-mask-load.rs b/tests/assembly/simd-intrinsic-mask-load.rs
index a0d0514c0141d..d3f3453a780a4 100644
--- a/tests/assembly/simd-intrinsic-mask-load.rs
+++ b/tests/assembly/simd-intrinsic-mask-load.rs
@@ -34,9 +34,8 @@ pub struct f64x4([f64; 4]);
 #[repr(simd)]
 pub struct m64x4([i64; 4]);
 
-extern "rust-intrinsic" {
-    fn simd_masked_load<M, P, T>(mask: M, pointer: P, values: T) -> T;
-}
+#[rustc_intrinsic]
+unsafe fn simd_masked_load<M, P, T>(mask: M, pointer: P, values: T) -> T;
 
 // CHECK-LABEL: load_i8x16
 #[no_mangle]
diff --git a/tests/assembly/simd-intrinsic-mask-reduce.rs b/tests/assembly/simd-intrinsic-mask-reduce.rs
index 959c4ddefdb0e..8b15ed0a254c6 100644
--- a/tests/assembly/simd-intrinsic-mask-reduce.rs
+++ b/tests/assembly/simd-intrinsic-mask-reduce.rs
@@ -20,10 +20,10 @@ use minicore::*;
 #[repr(simd)]
 pub struct mask8x16([i8; 16]);
 
-extern "rust-intrinsic" {
-    fn simd_reduce_all<T>(x: T) -> bool;
-    fn simd_reduce_any<T>(x: T) -> bool;
-}
+#[rustc_intrinsic]
+unsafe fn simd_reduce_all<T>(x: T) -> bool;
+#[rustc_intrinsic]
+unsafe fn simd_reduce_any<T>(x: T) -> bool;
 
 // CHECK-LABEL: mask_reduce_all:
 #[no_mangle]
diff --git a/tests/assembly/simd-intrinsic-mask-store.rs b/tests/assembly/simd-intrinsic-mask-store.rs
index 4be9194943c78..001762e5060db 100644
--- a/tests/assembly/simd-intrinsic-mask-store.rs
+++ b/tests/assembly/simd-intrinsic-mask-store.rs
@@ -34,9 +34,8 @@ pub struct f64x4([f64; 4]);
 #[repr(simd)]
 pub struct m64x4([i64; 4]);
 
-extern "rust-intrinsic" {
-    fn simd_masked_store<M, P, T>(mask: M, pointer: P, values: T);
-}
+#[rustc_intrinsic]
+unsafe fn simd_masked_store<M, P, T>(mask: M, pointer: P, values: T);
 
 // CHECK-LABEL: store_i8x16
 #[no_mangle]
diff --git a/tests/assembly/simd-intrinsic-scatter.rs b/tests/assembly/simd-intrinsic-scatter.rs
index 715de04af4d76..d77dfad3546d8 100644
--- a/tests/assembly/simd-intrinsic-scatter.rs
+++ b/tests/assembly/simd-intrinsic-scatter.rs
@@ -22,9 +22,8 @@ pub struct m64x4([i64; 4]);
 #[repr(simd)]
 pub struct pf64x4([*mut f64; 4]);
 
-extern "rust-intrinsic" {
-    fn simd_scatter<V, P, M>(values: V, pointer: P, mask: M);
-}
+#[rustc_intrinsic]
+unsafe fn simd_scatter<V, P, M>(values: V, pointer: P, mask: M);
 
 // CHECK-LABEL: scatter_f64x4
 #[no_mangle]
diff --git a/tests/assembly/simd-intrinsic-select.rs b/tests/assembly/simd-intrinsic-select.rs
index 7f1e42662bfb3..4f8d6b825b611 100644
--- a/tests/assembly/simd-intrinsic-select.rs
+++ b/tests/assembly/simd-intrinsic-select.rs
@@ -48,9 +48,8 @@ pub struct f64x8([f64; 8]);
 #[repr(simd)]
 pub struct m64x8([i64; 8]);
 
-extern "rust-intrinsic" {
-    fn simd_select<M, V>(mask: M, a: V, b: V) -> V;
-}
+#[rustc_intrinsic]
+unsafe fn simd_select<M, V>(mask: M, a: V, b: V) -> V;
 
 // CHECK-LABEL: select_i8x16
 #[no_mangle]
diff --git a/tests/codegen/avr/avr-func-addrspace.rs b/tests/codegen/avr/avr-func-addrspace.rs
index 2ae2f40d7b349..e0192f8b45ab8 100644
--- a/tests/codegen/avr/avr-func-addrspace.rs
+++ b/tests/codegen/avr/avr-func-addrspace.rs
@@ -17,9 +17,8 @@
 extern crate minicore;
 use minicore::*;
 
-extern "rust-intrinsic" {
-    pub fn transmute<Src, Dst>(src: Src) -> Dst;
-}
+#[rustc_intrinsic]
+pub unsafe fn transmute<Src, Dst>(src: Src) -> Dst;
 
 pub static mut STORAGE_FOO: fn(&usize, &mut u32) -> Result<(), ()> = arbitrary_black_box;
 pub static mut STORAGE_BAR: u32 = 12;
diff --git a/tests/codegen/emscripten-catch-unwind-js-eh.rs b/tests/codegen/emscripten-catch-unwind-js-eh.rs
index 018ad5454fc23..3ab4b5c9c6312 100644
--- a/tests/codegen/emscripten-catch-unwind-js-eh.rs
+++ b/tests/codegen/emscripten-catch-unwind-js-eh.rs
@@ -23,13 +23,12 @@ fn size_of<T>() -> usize {
     loop {}
 }
 
-extern "rust-intrinsic" {
-    fn catch_unwind(
-        try_fn: fn(_: *mut u8),
-        data: *mut u8,
-        catch_fn: fn(_: *mut u8, _: *mut u8),
-    ) -> i32;
-}
+#[rustc_intrinsic]
+unsafe fn catch_unwind(
+    try_fn: fn(_: *mut u8),
+    data: *mut u8,
+    catch_fn: fn(_: *mut u8, _: *mut u8),
+) -> i32;
 
 // CHECK-LABEL: @ptr_size
 #[no_mangle]
diff --git a/tests/codegen/emscripten-catch-unwind-wasm-eh.rs b/tests/codegen/emscripten-catch-unwind-wasm-eh.rs
index 0fc9ae96720e4..d0571e4df0816 100644
--- a/tests/codegen/emscripten-catch-unwind-wasm-eh.rs
+++ b/tests/codegen/emscripten-catch-unwind-wasm-eh.rs
@@ -21,14 +21,12 @@ impl<T> Copy for *mut T {}
 fn size_of<T>() -> usize {
     loop {}
 }
-
-extern "rust-intrinsic" {
-    fn catch_unwind(
-        try_fn: fn(_: *mut u8),
-        data: *mut u8,
-        catch_fn: fn(_: *mut u8, _: *mut u8),
-    ) -> i32;
-}
+#[rustc_intrinsic]
+unsafe fn catch_unwind(
+    try_fn: fn(_: *mut u8),
+    data: *mut u8,
+    catch_fn: fn(_: *mut u8, _: *mut u8),
+) -> i32;
 
 // CHECK-LABEL: @ptr_size
 #[no_mangle]
diff --git a/tests/codegen/intrinsic-no-unnamed-attr.rs b/tests/codegen/intrinsic-no-unnamed-attr.rs
index fce0de80d7b60..35eb025ab6bb6 100644
--- a/tests/codegen/intrinsic-no-unnamed-attr.rs
+++ b/tests/codegen/intrinsic-no-unnamed-attr.rs
@@ -2,9 +2,9 @@
 
 #![feature(intrinsics)]
 
-extern "rust-intrinsic" {
-    fn sqrtf32(x: f32) -> f32;
-}
+#[rustc_intrinsic]
+unsafe fn sqrtf32(x: f32) -> f32;
+
 // CHECK: @llvm.sqrt.f32(float) #{{[0-9]*}}
 
 fn main() {
diff --git a/tests/codegen/intrinsics/nontemporal.rs b/tests/codegen/intrinsics/nontemporal.rs
index 1d4fae83c29dd..a151d4bd29741 100644
--- a/tests/codegen/intrinsics/nontemporal.rs
+++ b/tests/codegen/intrinsics/nontemporal.rs
@@ -18,9 +18,8 @@
 extern crate minicore;
 use minicore::*;
 
-extern "rust-intrinsic" {
-    pub fn nontemporal_store<T>(ptr: *mut T, val: T);
-}
+#[rustc_intrinsic]
+pub unsafe fn nontemporal_store<T>(ptr: *mut T, val: T);
 
 #[no_mangle]
 pub fn a(a: &mut u32, b: u32) {
diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs
index 4859d93546196..5afddc5ff7301 100644
--- a/tests/mir-opt/lower_intrinsics.rs
+++ b/tests/mir-opt/lower_intrinsics.rs
@@ -153,11 +153,10 @@ pub fn discriminant<T>(t: T) {
     core::intrinsics::discriminant_value(&E::B);
 }
 
-extern "rust-intrinsic" {
-    // Cannot use `std::intrinsics::copy_nonoverlapping` as that is a wrapper function
-    #[rustc_nounwind]
-    fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
-}
+// Cannot use `std::intrinsics::copy_nonoverlapping` as that is a wrapper function
+#[rustc_nounwind]
+#[rustc_intrinsic]
+unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
 
 // EMIT_MIR lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff
 pub fn f_copy_nonoverlapping() {
diff --git a/tests/run-make/atomic-lock-free/atomic_lock_free.rs b/tests/run-make/atomic-lock-free/atomic_lock_free.rs
index 1f1116b9bfd17..b49c5044f31d6 100644
--- a/tests/run-make/atomic-lock-free/atomic_lock_free.rs
+++ b/tests/run-make/atomic-lock-free/atomic_lock_free.rs
@@ -2,9 +2,8 @@
 #![crate_type = "rlib"]
 #![no_core]
 
-extern "rust-intrinsic" {
-    fn atomic_xadd_seqcst<T>(dst: *mut T, src: T) -> T;
-}
+#[rustc_intrinsic]
+unsafe fn atomic_xadd_seqcst<T>(dst: *mut T, src: T) -> T;
 
 #[lang = "sized"]
 trait Sized {}
diff --git a/tests/run-make/avr-rjmp-offset/avr-rjmp-offsets.rs b/tests/run-make/avr-rjmp-offset/avr-rjmp-offsets.rs
index 2f97fc1ed95ab..c91cd695ceea8 100644
--- a/tests/run-make/avr-rjmp-offset/avr-rjmp-offsets.rs
+++ b/tests/run-make/avr-rjmp-offset/avr-rjmp-offsets.rs
@@ -37,10 +37,9 @@ mod minicore {
         #[inline]
         #[rustc_diagnostic_item = "ptr_write_volatile"]
         pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
-            extern "rust-intrinsic" {
-                #[rustc_nounwind]
-                pub fn volatile_store<T>(dst: *mut T, val: T);
-            }
+            #[rustc_intrinsic]
+            pub unsafe fn volatile_store<T>(dst: *mut T, val: T);
+
             unsafe { volatile_store(dst, src) };
         }
     }
diff --git a/tests/ui/abi/abi-typo-unstable.stderr b/tests/ui/abi/abi-typo-unstable.feature_disabled.stderr
similarity index 55%
rename from tests/ui/abi/abi-typo-unstable.stderr
rename to tests/ui/abi/abi-typo-unstable.feature_disabled.stderr
index 9ba67ad7dbe4a..1934b483c47a0 100644
--- a/tests/ui/abi/abi-typo-unstable.stderr
+++ b/tests/ui/abi/abi-typo-unstable.feature_disabled.stderr
@@ -1,8 +1,8 @@
-error[E0703]: invalid ABI: found `rust-intrinsec`
-  --> $DIR/abi-typo-unstable.rs:2:8
+error[E0703]: invalid ABI: found `rust-cull`
+  --> $DIR/abi-typo-unstable.rs:5:8
    |
-LL | extern "rust-intrinsec" fn rust_intrinsic() {}
-   |        ^^^^^^^^^^^^^^^^ invalid ABI
+LL | extern "rust-cull" fn rust_call(_: ()) {}
+   |        ^^^^^^^^^^^ invalid ABI
    |
    = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions
 
diff --git a/tests/ui/abi/abi-typo-unstable.feature_enabled.stderr b/tests/ui/abi/abi-typo-unstable.feature_enabled.stderr
new file mode 100644
index 0000000000000..868b9509830b0
--- /dev/null
+++ b/tests/ui/abi/abi-typo-unstable.feature_enabled.stderr
@@ -0,0 +1,16 @@
+error[E0703]: invalid ABI: found `rust-cull`
+  --> $DIR/abi-typo-unstable.rs:5:8
+   |
+LL | extern "rust-cull" fn rust_call(_: ()) {}
+   |        ^^^^^^^^^^^ invalid ABI
+   |
+   = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions
+help: there's a similarly named valid ABI `rust-call`
+   |
+LL - extern "rust-cull" fn rust_call(_: ()) {}
+LL + extern "rust-call" fn rust_call(_: ()) {}
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0703`.
diff --git a/tests/ui/abi/abi-typo-unstable.rs b/tests/ui/abi/abi-typo-unstable.rs
index 94991a5eb17e8..75366217fa26f 100644
--- a/tests/ui/abi/abi-typo-unstable.rs
+++ b/tests/ui/abi/abi-typo-unstable.rs
@@ -1,6 +1,11 @@
-// rust-intrinsic is unstable and not enabled, so it should not be suggested as a fix
-extern "rust-intrinsec" fn rust_intrinsic() {} //~ ERROR invalid ABI
+//@ revisions: feature_disabled feature_enabled
+#![cfg_attr(feature_enabled, feature(unboxed_closures))]
+
+// rust-call is unstable and not enabled, so it should not be suggested as a fix
+extern "rust-cull" fn rust_call(_: ()) {}
+//~^ ERROR invalid ABI
+//[feature_enabled]~| HELP there's a similarly named valid ABI
 
 fn main() {
-    rust_intrinsic();
+    rust_call(());
 }
diff --git a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
index d7d2161e7ad97..1be8db5ddf44f 100644
--- a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
+++ b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr
@@ -10,24 +10,6 @@ LL - fn get<T:Get,U:Get>(x: T, y: U) -> Get::Value {}
 LL + fn get<T:Get,U:Get>(x: T, y: U) -> <Example as Get>::Value {}
    |
 
-error[E0223]: ambiguous associated type
-  --> $DIR/associated-types-in-ambiguous-context.rs:13:23
-   |
-LL |     fn grab(&self) -> Grab::Value;
-   |                       ^^^^^^^^^^^ help: use fully-qualified syntax: `<Self as Grab>::Value`
-
-error[E0223]: ambiguous associated type
-  --> $DIR/associated-types-in-ambiguous-context.rs:16:22
-   |
-LL |     fn get(&self) -> Get::Value;
-   |                      ^^^^^^^^^^
-   |
-help: if there were a type named `Example` that implemented `Get`, you could use the fully-qualified path
-   |
-LL -     fn get(&self) -> Get::Value;
-LL +     fn get(&self) -> <Example as Get>::Value;
-   |
-
 error[E0223]: ambiguous associated type
   --> $DIR/associated-types-in-ambiguous-context.rs:22:17
    |
@@ -56,6 +38,24 @@ LL + type X = <IoSlice<'_> as Deref>::Target;
    |
      and N other candidates
 
+error[E0223]: ambiguous associated type
+  --> $DIR/associated-types-in-ambiguous-context.rs:13:23
+   |
+LL |     fn grab(&self) -> Grab::Value;
+   |                       ^^^^^^^^^^^ help: use fully-qualified syntax: `<Self as Grab>::Value`
+
+error[E0223]: ambiguous associated type
+  --> $DIR/associated-types-in-ambiguous-context.rs:16:22
+   |
+LL |     fn get(&self) -> Get::Value;
+   |                      ^^^^^^^^^^
+   |
+help: if there were a type named `Example` that implemented `Get`, you could use the fully-qualified path
+   |
+LL -     fn get(&self) -> Get::Value;
+LL +     fn get(&self) -> <Example as Get>::Value;
+   |
+
 error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0223`.
diff --git a/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr b/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr
index 3a6b8008fceb3..02d5231f7134d 100644
--- a/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr
+++ b/tests/ui/borrowck/ice-mutability-error-slicing-121807.stderr
@@ -23,12 +23,6 @@ LL |     extern "C" fn read_dword(Self::Assoc<'_>) -> u16;
    = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
    = note: `#[warn(anonymous_parameters)]` on by default
 
-error[E0220]: associated type `Assoc` not found for `Self`
-  --> $DIR/ice-mutability-error-slicing-121807.rs:7:36
-   |
-LL |     extern "C" fn read_dword(Self::Assoc<'_>) -> u16;
-   |                                    ^^^^^ associated type `Assoc` not found
-
 error[E0185]: method `read_dword` has a `&self` declaration in the impl, but not in the trait
   --> $DIR/ice-mutability-error-slicing-121807.rs:17:5
    |
@@ -47,6 +41,12 @@ LL |     extern "C" fn read_word(&mut self) -> u8;
 LL | impl MemoryUnit for ROM {
    | ^^^^^^^^^^^^^^^^^^^^^^^ missing `read_word` in implementation
 
+error[E0220]: associated type `Assoc` not found for `Self`
+  --> $DIR/ice-mutability-error-slicing-121807.rs:7:36
+   |
+LL |     extern "C" fn read_dword(Self::Assoc<'_>) -> u16;
+   |                                    ^^^^^ associated type `Assoc` not found
+
 error: aborting due to 4 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0046, E0185, E0220, E0261.
diff --git a/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr b/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr
index 190ddeaa8f285..a656bb67bcba0 100644
--- a/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr
+++ b/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr
@@ -8,12 +8,6 @@ LL |     extern "C" fn read_dword(Self::Assoc<'_>) -> u16;
    = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
    = note: `#[warn(anonymous_parameters)]` on by default
 
-error[E0220]: associated type `Assoc` not found for `Self`
-  --> $DIR/trait-impl-argument-difference-ice.rs:4:36
-   |
-LL |     extern "C" fn read_dword(Self::Assoc<'_>) -> u16;
-   |                                    ^^^^^ associated type `Assoc` not found
-
 error[E0185]: method `read_dword` has a `&self` declaration in the impl, but not in the trait
   --> $DIR/trait-impl-argument-difference-ice.rs:14:5
    |
@@ -32,6 +26,12 @@ LL |     extern "C" fn read_word(&mut self) -> u8;
 LL | impl MemoryUnit for ROM {
    | ^^^^^^^^^^^^^^^^^^^^^^^ missing `read_word` in implementation
 
+error[E0220]: associated type `Assoc` not found for `Self`
+  --> $DIR/trait-impl-argument-difference-ice.rs:4:36
+   |
+LL |     extern "C" fn read_dword(Self::Assoc<'_>) -> u16;
+   |                                    ^^^^^ associated type `Assoc` not found
+
 error[E0596]: cannot borrow `*self` as mutable, as it is behind a `&` reference
   --> $DIR/trait-impl-argument-difference-ice.rs:16:19
    |
diff --git a/tests/ui/delegation/ice-issue-124347.rs b/tests/ui/delegation/ice-issue-124347.rs
index b2b3c61a722b3..3e0a5b36ddcf3 100644
--- a/tests/ui/delegation/ice-issue-124347.rs
+++ b/tests/ui/delegation/ice-issue-124347.rs
@@ -4,7 +4,6 @@
 // FIXME(fn_delegation): `recursive delegation` error should be emitted here
 trait Trait {
     reuse Trait::foo { &self.0 }
-    //~^ ERROR recursive delegation is not supported yet
 }
 
 reuse foo;
diff --git a/tests/ui/delegation/ice-issue-124347.stderr b/tests/ui/delegation/ice-issue-124347.stderr
index 74c4b5cd949a3..2955c04420348 100644
--- a/tests/ui/delegation/ice-issue-124347.stderr
+++ b/tests/ui/delegation/ice-issue-124347.stderr
@@ -1,23 +1,17 @@
-error: recursive delegation is not supported yet
-  --> $DIR/ice-issue-124347.rs:6:18
-   |
-LL |     reuse Trait::foo { &self.0 }
-   |                  ^^^ callee defined here
-
 error[E0391]: cycle detected when computing generics of `foo`
-  --> $DIR/ice-issue-124347.rs:10:7
+  --> $DIR/ice-issue-124347.rs:9:7
    |
 LL | reuse foo;
    |       ^^^
    |
    = note: ...which immediately requires computing generics of `foo` again
 note: cycle used when checking that `foo` is well-formed
-  --> $DIR/ice-issue-124347.rs:10:7
+  --> $DIR/ice-issue-124347.rs:9:7
    |
 LL | reuse foo;
    |       ^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/dyn-compatibility/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr b/tests/ui/dyn-compatibility/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr
index 832e7ef4dc38c..2cf244185e697 100644
--- a/tests/ui/dyn-compatibility/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr
+++ b/tests/ui/dyn-compatibility/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.stderr
@@ -187,166 +187,6 @@ help: consider using the `'static` lifetime, but this is uncommon unless you're
 LL | fn parrot() -> &'static mut Trait {
    |                 +++++++
 
-error[E0782]: expected a type, found a trait
-  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:52:16
-   |
-LL |     fn foo(_: &Trait);
-   |                ^^^^^
-   |
-help: use a new generic type parameter, constrained by `Trait`
-   |
-LL -     fn foo(_: &Trait);
-LL +     fn foo<T: Trait>(_: &T);
-   |
-help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
-   |
-LL |     fn foo(_: &impl Trait);
-   |                ++++
-help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
-   |
-LL |     fn foo(_: &dyn Trait);
-   |                +++
-
-error[E0782]: expected a type, found a trait
-  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:55:19
-   |
-LL |     fn bar(_: &'a Trait);
-   |                   ^^^^^
-   |
-help: use a new generic type parameter, constrained by `Trait`
-   |
-LL -     fn bar(_: &'a Trait);
-LL +     fn bar<T: Trait>(_: &'a T);
-   |
-help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
-   |
-LL |     fn bar(_: &'a impl Trait);
-   |                   ++++
-help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
-   |
-LL |     fn bar(_: &'a dyn Trait);
-   |                   +++
-
-error[E0782]: expected a type, found a trait
-  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:59:22
-   |
-LL |     fn alice<'a>(_: &Trait);
-   |                      ^^^^^
-   |
-help: use a new generic type parameter, constrained by `Trait`
-   |
-LL -     fn alice<'a>(_: &Trait);
-LL +     fn alice<'a, T: Trait>(_: &T);
-   |
-help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
-   |
-LL |     fn alice<'a>(_: &impl Trait);
-   |                      ++++
-help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
-   |
-LL |     fn alice<'a>(_: &dyn Trait);
-   |                      +++
-
-error[E0782]: expected a type, found a trait
-  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:62:23
-   |
-LL |     fn bob<'a>(_: &'a Trait);
-   |                       ^^^^^
-   |
-help: use a new generic type parameter, constrained by `Trait`
-   |
-LL -     fn bob<'a>(_: &'a Trait);
-LL +     fn bob<'a, T: Trait>(_: &'a T);
-   |
-help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
-   |
-LL |     fn bob<'a>(_: &'a impl Trait);
-   |                       ++++
-help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
-   |
-LL |     fn bob<'a>(_: &'a dyn Trait);
-   |                       +++
-
-error[E0782]: expected a type, found a trait
-  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:65:18
-   |
-LL |     fn cat() -> &Trait;
-   |                  ^^^^^
-   |
-help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
-   |
-LL |     fn cat() -> &impl Trait;
-   |                  ++++
-help: alternatively, you can return an owned trait object
-   |
-LL -     fn cat() -> &Trait;
-LL +     fn cat() -> Box<dyn Trait>;
-   |
-
-error[E0782]: expected a type, found a trait
-  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:69:22
-   |
-LL |     fn dog<'a>() -> &Trait {
-   |                      ^^^^^
-   |
-help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
-   |
-LL |     fn dog<'a>() -> &impl Trait {
-   |                      ++++
-help: alternatively, you can return an owned trait object
-   |
-LL -     fn dog<'a>() -> &Trait {
-LL +     fn dog<'a>() -> Box<dyn Trait> {
-   |
-
-error[E0782]: expected a type, found a trait
-  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:75:24
-   |
-LL |     fn kitten() -> &'a Trait {
-   |                        ^^^^^
-   |
-help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
-   |
-LL |     fn kitten() -> &'a impl Trait {
-   |                        ++++
-help: alternatively, you can return an owned trait object
-   |
-LL -     fn kitten() -> &'a Trait {
-LL +     fn kitten() -> Box<dyn Trait> {
-   |
-
-error[E0782]: expected a type, found a trait
-  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:81:27
-   |
-LL |     fn puppy<'a>() -> &'a Trait {
-   |                           ^^^^^
-   |
-help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
-   |
-LL |     fn puppy<'a>() -> &'a impl Trait {
-   |                           ++++
-help: alternatively, you can return an owned trait object
-   |
-LL -     fn puppy<'a>() -> &'a Trait {
-LL +     fn puppy<'a>() -> Box<dyn Trait> {
-   |
-
-error[E0782]: expected a type, found a trait
-  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:86:25
-   |
-LL |     fn parrot() -> &mut Trait {
-   |                         ^^^^^
-   |
-help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
-   |
-LL |     fn parrot() -> &mut impl Trait {
-   |                         ++++
-help: alternatively, you can return an owned trait object
-   |
-LL -     fn parrot() -> &mut Trait {
-LL +     fn parrot() -> Box<dyn Trait> {
-   |
-
 error[E0782]: expected a type, found a trait
   --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:93:12
    |
@@ -667,6 +507,166 @@ LL -     fn parrot() -> &mut Trait {
 LL +     fn parrot() -> Box<dyn Trait> {
    |
 
+error[E0782]: expected a type, found a trait
+  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:52:16
+   |
+LL |     fn foo(_: &Trait);
+   |                ^^^^^
+   |
+help: use a new generic type parameter, constrained by `Trait`
+   |
+LL -     fn foo(_: &Trait);
+LL +     fn foo<T: Trait>(_: &T);
+   |
+help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
+   |
+LL |     fn foo(_: &impl Trait);
+   |                ++++
+help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
+   |
+LL |     fn foo(_: &dyn Trait);
+   |                +++
+
+error[E0782]: expected a type, found a trait
+  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:55:19
+   |
+LL |     fn bar(_: &'a Trait);
+   |                   ^^^^^
+   |
+help: use a new generic type parameter, constrained by `Trait`
+   |
+LL -     fn bar(_: &'a Trait);
+LL +     fn bar<T: Trait>(_: &'a T);
+   |
+help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
+   |
+LL |     fn bar(_: &'a impl Trait);
+   |                   ++++
+help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
+   |
+LL |     fn bar(_: &'a dyn Trait);
+   |                   +++
+
+error[E0782]: expected a type, found a trait
+  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:59:22
+   |
+LL |     fn alice<'a>(_: &Trait);
+   |                      ^^^^^
+   |
+help: use a new generic type parameter, constrained by `Trait`
+   |
+LL -     fn alice<'a>(_: &Trait);
+LL +     fn alice<'a, T: Trait>(_: &T);
+   |
+help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
+   |
+LL |     fn alice<'a>(_: &impl Trait);
+   |                      ++++
+help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
+   |
+LL |     fn alice<'a>(_: &dyn Trait);
+   |                      +++
+
+error[E0782]: expected a type, found a trait
+  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:62:23
+   |
+LL |     fn bob<'a>(_: &'a Trait);
+   |                       ^^^^^
+   |
+help: use a new generic type parameter, constrained by `Trait`
+   |
+LL -     fn bob<'a>(_: &'a Trait);
+LL +     fn bob<'a, T: Trait>(_: &'a T);
+   |
+help: you can also use an opaque type, but users won't be able to specify the type parameter when calling the `fn`, having to rely exclusively on type inference
+   |
+LL |     fn bob<'a>(_: &'a impl Trait);
+   |                       ++++
+help: alternatively, use a trait object to accept any type that implements `Trait`, accessing its methods at runtime using dynamic dispatch
+   |
+LL |     fn bob<'a>(_: &'a dyn Trait);
+   |                       +++
+
+error[E0782]: expected a type, found a trait
+  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:65:18
+   |
+LL |     fn cat() -> &Trait;
+   |                  ^^^^^
+   |
+help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
+   |
+LL |     fn cat() -> &impl Trait;
+   |                  ++++
+help: alternatively, you can return an owned trait object
+   |
+LL -     fn cat() -> &Trait;
+LL +     fn cat() -> Box<dyn Trait>;
+   |
+
+error[E0782]: expected a type, found a trait
+  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:69:22
+   |
+LL |     fn dog<'a>() -> &Trait {
+   |                      ^^^^^
+   |
+help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
+   |
+LL |     fn dog<'a>() -> &impl Trait {
+   |                      ++++
+help: alternatively, you can return an owned trait object
+   |
+LL -     fn dog<'a>() -> &Trait {
+LL +     fn dog<'a>() -> Box<dyn Trait> {
+   |
+
+error[E0782]: expected a type, found a trait
+  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:75:24
+   |
+LL |     fn kitten() -> &'a Trait {
+   |                        ^^^^^
+   |
+help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
+   |
+LL |     fn kitten() -> &'a impl Trait {
+   |                        ++++
+help: alternatively, you can return an owned trait object
+   |
+LL -     fn kitten() -> &'a Trait {
+LL +     fn kitten() -> Box<dyn Trait> {
+   |
+
+error[E0782]: expected a type, found a trait
+  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:81:27
+   |
+LL |     fn puppy<'a>() -> &'a Trait {
+   |                           ^^^^^
+   |
+help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
+   |
+LL |     fn puppy<'a>() -> &'a impl Trait {
+   |                           ++++
+help: alternatively, you can return an owned trait object
+   |
+LL -     fn puppy<'a>() -> &'a Trait {
+LL +     fn puppy<'a>() -> Box<dyn Trait> {
+   |
+
+error[E0782]: expected a type, found a trait
+  --> $DIR/reference-to-bare-trait-in-fn-inputs-and-outputs-issue-125139.rs:86:25
+   |
+LL |     fn parrot() -> &mut Trait {
+   |                         ^^^^^
+   |
+help: use `impl Trait` to return an opaque type, as long as you return a single underlying type
+   |
+LL |     fn parrot() -> &mut impl Trait {
+   |                         ++++
+help: alternatively, you can return an owned trait object
+   |
+LL -     fn parrot() -> &mut Trait {
+LL +     fn parrot() -> Box<dyn Trait> {
+   |
+
 error: aborting due to 42 previous errors
 
 Some errors have detailed explanations: E0106, E0261, E0782.
diff --git a/tests/ui/error-codes/E0092.rs b/tests/ui/error-codes/E0092.rs
index ddaace98bd4af..19a7c65a48ed2 100644
--- a/tests/ui/error-codes/E0092.rs
+++ b/tests/ui/error-codes/E0092.rs
@@ -1,7 +1,6 @@
 #![feature(intrinsics)]
-extern "rust-intrinsic" {
-    fn atomic_foo(); //~ ERROR E0092
-}
 
-fn main() {
-}
+#[rustc_intrinsic]
+unsafe fn atomic_foo(); //~ ERROR E0092
+
+fn main() {}
diff --git a/tests/ui/error-codes/E0092.stderr b/tests/ui/error-codes/E0092.stderr
index 4ff2e6f077d24..003c989fd5961 100644
--- a/tests/ui/error-codes/E0092.stderr
+++ b/tests/ui/error-codes/E0092.stderr
@@ -1,8 +1,8 @@
 error[E0092]: unrecognized atomic operation function: `foo`
-  --> $DIR/E0092.rs:3:5
+  --> $DIR/E0092.rs:4:11
    |
-LL |     fn atomic_foo();
-   |     ^^^^^^^^^^^^^^^^ unrecognized atomic operation
+LL | unsafe fn atomic_foo();
+   |           ^^^^^^^^^^ unrecognized atomic operation
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0093.rs b/tests/ui/error-codes/E0093.rs
index a2f0b1ae44379..24df7a9a32b97 100644
--- a/tests/ui/error-codes/E0093.rs
+++ b/tests/ui/error-codes/E0093.rs
@@ -1,8 +1,7 @@
 #![feature(intrinsics)]
-extern "rust-intrinsic" {
-    fn foo();
-    //~^ ERROR E0093
-}
 
-fn main() {
-}
+#[rustc_intrinsic]
+unsafe fn foo();
+//~^ ERROR E0093
+
+fn main() {}
diff --git a/tests/ui/error-codes/E0093.stderr b/tests/ui/error-codes/E0093.stderr
index 51c367b343ab1..d81bf53976aee 100644
--- a/tests/ui/error-codes/E0093.stderr
+++ b/tests/ui/error-codes/E0093.stderr
@@ -1,8 +1,8 @@
 error[E0093]: unrecognized intrinsic function: `foo`
-  --> $DIR/E0093.rs:3:5
+  --> $DIR/E0093.rs:4:11
    |
-LL |     fn foo();
-   |     ^^^^^^^^^ unrecognized intrinsic
+LL | unsafe fn foo();
+   |           ^^^ unrecognized intrinsic
    |
    = help: if you're adding an intrinsic, be sure to update `check_intrinsic_type`
 
diff --git a/tests/ui/error-codes/E0622.rs b/tests/ui/error-codes/E0622.rs
index 08c6d17129604..0c2a4f226d80c 100644
--- a/tests/ui/error-codes/E0622.rs
+++ b/tests/ui/error-codes/E0622.rs
@@ -1,6 +1,14 @@
 #![feature(intrinsics)]
-extern "rust-intrinsic" {
-    pub static atomic_singlethreadfence_seqcst : unsafe extern "rust-intrinsic" fn();
+
+extern "C" {
+
+    #[rustc_intrinsic]
+    pub static atomic_singlethreadfence_seqcst: unsafe extern "C" fn();
     //~^ ERROR intrinsic must be a function [E0622]
 }
-fn main() { unsafe { atomic_singlethreadfence_seqcst(); } }
+
+fn main() {
+    unsafe {
+        atomic_singlethreadfence_seqcst();
+    }
+}
diff --git a/tests/ui/error-codes/E0622.stderr b/tests/ui/error-codes/E0622.stderr
index 739ec984fc606..c0aea542af04e 100644
--- a/tests/ui/error-codes/E0622.stderr
+++ b/tests/ui/error-codes/E0622.stderr
@@ -1,8 +1,8 @@
 error[E0622]: intrinsic must be a function
-  --> $DIR/E0622.rs:3:5
+  --> $DIR/E0622.rs:6:5
    |
-LL |     pub static atomic_singlethreadfence_seqcst : unsafe extern "rust-intrinsic" fn();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected a function
+LL |     pub static atomic_singlethreadfence_seqcst: unsafe extern "C" fn();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected a function
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/extern/extern-with-type-bounds.rs b/tests/ui/extern/extern-with-type-bounds.rs
deleted file mode 100644
index 3fbddfc99a6fa..0000000000000
--- a/tests/ui/extern/extern-with-type-bounds.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-#![feature(intrinsics, rustc_attrs)]
-
-// Intrinsics are the only (?) extern blocks supporting generics.
-// Once intrinsics have to be declared via `#[rustc_intrinsic]`,
-// the entire support for generics in extern fn can probably be removed.
-
-extern "rust-intrinsic" {
-    // Silent bounds made explicit to make sure they are actually
-    // resolved.
-    fn transmute<T: Sized, U: Sized>(val: T) -> U;
-
-    // Bounds aren't checked right now, so this should work
-    // even though it's incorrect.
-    fn size_of_val<T: Clone>(x: *const T) -> usize;
-
-    // Unresolved bounds should still error.
-    fn align_of<T: NoSuchTrait>() -> usize;
-    //~^ ERROR cannot find trait `NoSuchTrait` in this scope
-}
-
-fn main() {}
diff --git a/tests/ui/extern/extern-with-type-bounds.stderr b/tests/ui/extern/extern-with-type-bounds.stderr
deleted file mode 100644
index 893947e831fd7..0000000000000
--- a/tests/ui/extern/extern-with-type-bounds.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0405]: cannot find trait `NoSuchTrait` in this scope
-  --> $DIR/extern-with-type-bounds.rs:17:20
-   |
-LL |     fn align_of<T: NoSuchTrait>() -> usize;
-   |                    ^^^^^^^^^^^ not found in this scope
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0405`.
diff --git a/tests/ui/feature-gates/feature-gate-abi.rs b/tests/ui/feature-gates/feature-gate-abi.rs
index 2af623734ee87..bafd3643788e0 100644
--- a/tests/ui/feature-gates/feature-gate-abi.rs
+++ b/tests/ui/feature-gates/feature-gate-abi.rs
@@ -8,19 +8,10 @@
 extern crate minicore;
 use minicore::*;
 
-// Functions
-extern "rust-intrinsic" fn f1() {} //~ ERROR extern "rust-intrinsic" ABI is an implementation detail
-                                   //~^ ERROR intrinsic must be in
-extern "rust-intrinsic" fn f2() {} //~ ERROR extern "rust-intrinsic" ABI is an implementation detail
-                                       //~^ ERROR intrinsic must be in
 extern "rust-call" fn f4(_: ()) {} //~ ERROR extern "rust-call" ABI is experimental and subject to change
 
 // Methods in trait definition
 trait Tr {
-    extern "rust-intrinsic" fn m1(); //~ ERROR extern "rust-intrinsic" ABI is an implementation detail
-                                     //~^ ERROR intrinsic must be in
-    extern "rust-intrinsic" fn m2(); //~ ERROR extern "rust-intrinsic" ABI is an implementation detail
-                                         //~^ ERROR intrinsic must be in
     extern "rust-call" fn m4(_: ()); //~ ERROR extern "rust-call" ABI is experimental and subject to change
 
     extern "rust-call" fn dm4(_: ()) {} //~ ERROR extern "rust-call" ABI is experimental and subject to change
@@ -30,28 +21,16 @@ struct S;
 
 // Methods in trait impl
 impl Tr for S {
-    extern "rust-intrinsic" fn m1() {} //~ ERROR extern "rust-intrinsic" ABI is an implementation detail
-                                       //~^ ERROR intrinsic must be in
-    extern "rust-intrinsic" fn m2() {} //~ ERROR extern "rust-intrinsic" ABI is an implementation detail
-                                           //~^ ERROR intrinsic must be in
     extern "rust-call" fn m4(_: ()) {} //~ ERROR extern "rust-call" ABI is experimental and subject to change
 }
 
 // Methods in inherent impl
 impl S {
-    extern "rust-intrinsic" fn im1() {} //~ ERROR extern "rust-intrinsic" ABI is an implementation detail
-                                        //~^ ERROR intrinsic must be in
-    extern "rust-intrinsic" fn im2() {} //~ ERROR extern "rust-intrinsic" ABI is an implementation detail
-                                            //~^ ERROR intrinsic must be in
     extern "rust-call" fn im4(_: ()) {} //~ ERROR extern "rust-call" ABI is experimental and subject to change
 }
 
 // Function pointer types
-type A1 = extern "rust-intrinsic" fn(); //~ ERROR extern "rust-intrinsic" ABI is an implementation detail
-type A2 = extern "rust-intrinsic" fn(); //~ ERROR extern "rust-intrinsic" ABI is an implementation detail
 type A4 = extern "rust-call" fn(_: ()); //~ ERROR extern "rust-call" ABI is experimental and subject to change
 
 // Foreign modules
-extern "rust-intrinsic" {} //~ ERROR extern "rust-intrinsic" ABI is an implementation detail
-extern "rust-intrinsic" {} //~ ERROR extern "rust-intrinsic" ABI is an implementation detail
 extern "rust-call" {} //~ ERROR extern "rust-call" ABI is experimental and subject to change
diff --git a/tests/ui/feature-gates/feature-gate-abi.stderr b/tests/ui/feature-gates/feature-gate-abi.stderr
index a974c0099cbde..7897a60b34f44 100644
--- a/tests/ui/feature-gates/feature-gate-abi.stderr
+++ b/tests/ui/feature-gates/feature-gate-abi.stderr
@@ -1,23 +1,5 @@
-error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable
-  --> $DIR/feature-gate-abi.rs:12:8
-   |
-LL | extern "rust-intrinsic" fn f1() {}
-   |        ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(intrinsics)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable
-  --> $DIR/feature-gate-abi.rs:14:8
-   |
-LL | extern "rust-intrinsic" fn f2() {}
-   |        ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(intrinsics)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
 error[E0658]: the extern "rust-call" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:16:8
+  --> $DIR/feature-gate-abi.rs:11:8
    |
 LL | extern "rust-call" fn f4(_: ()) {}
    |        ^^^^^^^^^^^
@@ -26,26 +8,8 @@ LL | extern "rust-call" fn f4(_: ()) {}
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable
-  --> $DIR/feature-gate-abi.rs:20:12
-   |
-LL |     extern "rust-intrinsic" fn m1();
-   |            ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(intrinsics)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable
-  --> $DIR/feature-gate-abi.rs:22:12
-   |
-LL |     extern "rust-intrinsic" fn m2();
-   |            ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(intrinsics)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
 error[E0658]: the extern "rust-call" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:24:12
+  --> $DIR/feature-gate-abi.rs:15:12
    |
 LL |     extern "rust-call" fn m4(_: ());
    |            ^^^^^^^^^^^
@@ -55,7 +19,7 @@ LL |     extern "rust-call" fn m4(_: ());
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: the extern "rust-call" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:26:12
+  --> $DIR/feature-gate-abi.rs:17:12
    |
 LL |     extern "rust-call" fn dm4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -64,26 +28,8 @@ LL |     extern "rust-call" fn dm4(_: ()) {}
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable
-  --> $DIR/feature-gate-abi.rs:33:12
-   |
-LL |     extern "rust-intrinsic" fn m1() {}
-   |            ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(intrinsics)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable
-  --> $DIR/feature-gate-abi.rs:35:12
-   |
-LL |     extern "rust-intrinsic" fn m2() {}
-   |            ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(intrinsics)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
 error[E0658]: the extern "rust-call" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:37:12
+  --> $DIR/feature-gate-abi.rs:24:12
    |
 LL |     extern "rust-call" fn m4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -92,26 +38,8 @@ LL |     extern "rust-call" fn m4(_: ()) {}
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable
-  --> $DIR/feature-gate-abi.rs:42:12
-   |
-LL |     extern "rust-intrinsic" fn im1() {}
-   |            ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(intrinsics)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable
-  --> $DIR/feature-gate-abi.rs:44:12
-   |
-LL |     extern "rust-intrinsic" fn im2() {}
-   |            ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(intrinsics)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
 error[E0658]: the extern "rust-call" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:46:12
+  --> $DIR/feature-gate-abi.rs:29:12
    |
 LL |     extern "rust-call" fn im4(_: ()) {}
    |            ^^^^^^^^^^^
@@ -120,26 +48,8 @@ LL |     extern "rust-call" fn im4(_: ()) {}
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable
-  --> $DIR/feature-gate-abi.rs:50:18
-   |
-LL | type A1 = extern "rust-intrinsic" fn();
-   |                  ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(intrinsics)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable
-  --> $DIR/feature-gate-abi.rs:51:18
-   |
-LL | type A2 = extern "rust-intrinsic" fn();
-   |                  ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(intrinsics)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
 error[E0658]: the extern "rust-call" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:52:18
+  --> $DIR/feature-gate-abi.rs:33:18
    |
 LL | type A4 = extern "rust-call" fn(_: ());
    |                  ^^^^^^^^^^^
@@ -148,26 +58,8 @@ LL | type A4 = extern "rust-call" fn(_: ());
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable
-  --> $DIR/feature-gate-abi.rs:55:8
-   |
-LL | extern "rust-intrinsic" {}
-   |        ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(intrinsics)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable
-  --> $DIR/feature-gate-abi.rs:56:8
-   |
-LL | extern "rust-intrinsic" {}
-   |        ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(intrinsics)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
 error[E0658]: the extern "rust-call" ABI is experimental and subject to change
-  --> $DIR/feature-gate-abi.rs:57:8
+  --> $DIR/feature-gate-abi.rs:36:8
    |
 LL | extern "rust-call" {}
    |        ^^^^^^^^^^^
@@ -176,54 +68,6 @@ LL | extern "rust-call" {}
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:20:32
-   |
-LL |     extern "rust-intrinsic" fn m1();
-   |                                ^^
-
-error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:22:32
-   |
-LL |     extern "rust-intrinsic" fn m2();
-   |                                ^^
-
-error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:12:33
-   |
-LL | extern "rust-intrinsic" fn f1() {}
-   |                                 ^^
-
-error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:14:33
-   |
-LL | extern "rust-intrinsic" fn f2() {}
-   |                                 ^^
-
-error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:33:37
-   |
-LL |     extern "rust-intrinsic" fn m1() {}
-   |                                     ^^
-
-error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:35:37
-   |
-LL |     extern "rust-intrinsic" fn m2() {}
-   |                                     ^^
-
-error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:42:38
-   |
-LL |     extern "rust-intrinsic" fn im1() {}
-   |                                      ^^
-
-error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-abi.rs:44:38
-   |
-LL |     extern "rust-intrinsic" fn im2() {}
-   |                                      ^^
-
-error: aborting due to 27 previous errors
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-intrinsics.rs b/tests/ui/feature-gates/feature-gate-intrinsics.rs
index 65806a0223e74..b7ebba672728d 100644
--- a/tests/ui/feature-gates/feature-gate-intrinsics.rs
+++ b/tests/ui/feature-gates/feature-gate-intrinsics.rs
@@ -1,8 +1,5 @@
-extern "rust-intrinsic" {   //~ ERROR "rust-intrinsic" ABI is an implementation detail
-    fn bar(); //~ ERROR unrecognized intrinsic function: `bar`
-}
-
-extern "rust-intrinsic" fn baz() {} //~ ERROR "rust-intrinsic" ABI is an implementation detail
-//~^ ERROR intrinsic must be in
+#[rustc_intrinsic]
+//~^ ERROR the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items
+fn bar();
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-intrinsics.stderr b/tests/ui/feature-gates/feature-gate-intrinsics.stderr
index 97246f05258f0..a7a725883a928 100644
--- a/tests/ui/feature-gates/feature-gate-intrinsics.stderr
+++ b/tests/ui/feature-gates/feature-gate-intrinsics.stderr
@@ -1,36 +1,12 @@
-error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable
-  --> $DIR/feature-gate-intrinsics.rs:1:8
+error[E0658]: the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items
+  --> $DIR/feature-gate-intrinsics.rs:1:1
    |
-LL | extern "rust-intrinsic" {
-   |        ^^^^^^^^^^^^^^^^
+LL | #[rustc_intrinsic]
+   | ^^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable
-  --> $DIR/feature-gate-intrinsics.rs:5:8
-   |
-LL | extern "rust-intrinsic" fn baz() {}
-   |        ^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(intrinsics)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0093]: unrecognized intrinsic function: `bar`
-  --> $DIR/feature-gate-intrinsics.rs:2:5
-   |
-LL |     fn bar();
-   |     ^^^^^^^^^ unrecognized intrinsic
-   |
-   = help: if you're adding an intrinsic, be sure to update `check_intrinsic_type`
-
-error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/feature-gate-intrinsics.rs:5:34
-   |
-LL | extern "rust-intrinsic" fn baz() {}
-   |                                  ^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0093, E0658.
-For more information about an error, try `rustc --explain E0093`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.rs b/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.rs
index 2328798d74c32..44c0f1130f05d 100644
--- a/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.rs
+++ b/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.rs
@@ -5,9 +5,9 @@
 fn main() {
     let a = &[1, 2, 3];
     println!("{}", {
-        extern "rust-intrinsic" { //~ ERROR "rust-intrinsic" ABI is an implementation detail
-            fn atomic_fence();
-        }
+        #[rustc_intrinsic] //~ ERROR the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items
+        unsafe fn atomic_fence();
+
         atomic_fence(); //~ ERROR: is unsafe
         42
     });
diff --git a/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.stderr b/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.stderr
index 86f88fdff5fc8..aaaaeece67a84 100644
--- a/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.stderr
+++ b/tests/ui/feature-gates/feature-gated-feature-in-macro-arg.stderr
@@ -1,13 +1,13 @@
-error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable
-  --> $DIR/feature-gated-feature-in-macro-arg.rs:8:16
+error[E0658]: the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items
+  --> $DIR/feature-gated-feature-in-macro-arg.rs:8:9
    |
-LL |         extern "rust-intrinsic" {
-   |                ^^^^^^^^^^^^^^^^
+LL |         #[rustc_intrinsic]
+   |         ^^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0133]: call to unsafe function `main::atomic_fence` is unsafe and requires unsafe function or block
+error[E0133]: call to unsafe function `atomic_fence` is unsafe and requires unsafe function or block
   --> $DIR/feature-gated-feature-in-macro-arg.rs:11:9
    |
 LL |         atomic_fence();
diff --git a/tests/ui/intrinsics/always-extern.rs b/tests/ui/intrinsics/always-extern.rs
deleted file mode 100644
index 0afd8353455f2..0000000000000
--- a/tests/ui/intrinsics/always-extern.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-#![feature(intrinsics)]
-
-trait Foo {
-    extern "rust-intrinsic" fn foo(&self); //~ ERROR intrinsic must
-}
-
-impl Foo for () {
-    extern "rust-intrinsic" fn foo(&self) { //~ ERROR intrinsic must
-    }
-}
-
-extern "rust-intrinsic" fn hello() {//~ ERROR intrinsic must
-    //~^ ERROR unrecognized intrinsic function: `hello`
-}
-
-fn main() {
-}
diff --git a/tests/ui/intrinsics/always-extern.stderr b/tests/ui/intrinsics/always-extern.stderr
deleted file mode 100644
index 44b889c6faac6..0000000000000
--- a/tests/ui/intrinsics/always-extern.stderr
+++ /dev/null
@@ -1,34 +0,0 @@
-error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/always-extern.rs:4:32
-   |
-LL |     extern "rust-intrinsic" fn foo(&self);
-   |                                ^^^
-
-error[E0093]: unrecognized intrinsic function: `hello`
-  --> $DIR/always-extern.rs:12:28
-   |
-LL | extern "rust-intrinsic" fn hello() {
-   |                            ^^^^^ unrecognized intrinsic
-   |
-   = help: if you're adding an intrinsic, be sure to update `check_intrinsic_type`
-
-error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/always-extern.rs:8:43
-   |
-LL |       extern "rust-intrinsic" fn foo(&self) {
-   |  ___________________________________________^
-LL | |     }
-   | |_____^
-
-error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/always-extern.rs:12:36
-   |
-LL |   extern "rust-intrinsic" fn hello() {
-   |  ____________________________________^
-LL | |
-LL | | }
-   | |_^
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0093`.
diff --git a/tests/ui/intrinsics/auxiliary/cci_intrinsic.rs b/tests/ui/intrinsics/auxiliary/cci_intrinsic.rs
index f3b9d569ce3b1..1014ac6f5609e 100644
--- a/tests/ui/intrinsics/auxiliary/cci_intrinsic.rs
+++ b/tests/ui/intrinsics/auxiliary/cci_intrinsic.rs
@@ -1,14 +1,11 @@
 #![feature(intrinsics)]
 
 pub mod rusti {
-    extern "rust-intrinsic" {
-        pub fn atomic_xchg_seqcst<T>(dst: *mut T, src: T) -> T;
-    }
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_xchg_seqcst<T>(dst: *mut T, src: T) -> T;
 }
 
 #[inline(always)]
 pub fn atomic_xchg_seqcst(dst: *mut isize, src: isize) -> isize {
-    unsafe {
-        rusti::atomic_xchg_seqcst(dst, src)
-    }
+    unsafe { rusti::atomic_xchg_seqcst(dst, src) }
 }
diff --git a/tests/ui/intrinsics/incorrect-read_via_copy-defn.rs b/tests/ui/intrinsics/incorrect-read_via_copy-defn.rs
index 5520430e140b3..e9f9270de87f3 100644
--- a/tests/ui/intrinsics/incorrect-read_via_copy-defn.rs
+++ b/tests/ui/intrinsics/incorrect-read_via_copy-defn.rs
@@ -1,7 +1,8 @@
 fn main() {
     read_via_copy();
+    //~^ ERROR call to unsafe function `read_via_copy` is unsafe and requires unsafe function or block
 }
 
-extern "rust-intrinsic" fn read_via_copy() {}
-//~^ ERROR "rust-intrinsic" ABI is an implementation detail
-//~| ERROR intrinsic must be in `extern "rust-intrinsic" { ... }` block
+#[rustc_intrinsic]
+//~^ ERROR the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items
+unsafe fn read_via_copy() {}
diff --git a/tests/ui/intrinsics/incorrect-read_via_copy-defn.stderr b/tests/ui/intrinsics/incorrect-read_via_copy-defn.stderr
index c6682693f7409..6711c77a11eb3 100644
--- a/tests/ui/intrinsics/incorrect-read_via_copy-defn.stderr
+++ b/tests/ui/intrinsics/incorrect-read_via_copy-defn.stderr
@@ -1,18 +1,21 @@
-error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable
-  --> $DIR/incorrect-read_via_copy-defn.rs:5:8
+error[E0658]: the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items
+  --> $DIR/incorrect-read_via_copy-defn.rs:6:1
    |
-LL | extern "rust-intrinsic" fn read_via_copy() {}
-   |        ^^^^^^^^^^^^^^^^
+LL | #[rustc_intrinsic]
+   | ^^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/incorrect-read_via_copy-defn.rs:5:44
+error[E0133]: call to unsafe function `read_via_copy` is unsafe and requires unsafe function or block
+  --> $DIR/incorrect-read_via_copy-defn.rs:2:5
    |
-LL | extern "rust-intrinsic" fn read_via_copy() {}
-   |                                            ^^
+LL |     read_via_copy();
+   |     ^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0133, E0658.
+For more information about an error, try `rustc --explain E0133`.
diff --git a/tests/ui/intrinsics/incorrect-transmute.rs b/tests/ui/intrinsics/incorrect-transmute.rs
index 15d1ab939ed0b..25fbc7a92ee7c 100644
--- a/tests/ui/intrinsics/incorrect-transmute.rs
+++ b/tests/ui/intrinsics/incorrect-transmute.rs
@@ -1,7 +1,8 @@
 fn main() {
     transmute(); // does not ICE
+    //~^ ERROR call to unsafe function `transmute` is unsafe and requires unsafe function or block
 }
 
-extern "rust-intrinsic" fn transmute() {}
-//~^ ERROR "rust-intrinsic" ABI is an implementation detail
-//~| ERROR intrinsic must be in `extern "rust-intrinsic" { ... }` block
+#[rustc_intrinsic]
+//~^ ERROR the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items
+unsafe fn transmute() {}
diff --git a/tests/ui/intrinsics/incorrect-transmute.stderr b/tests/ui/intrinsics/incorrect-transmute.stderr
index 99dfb9847ff2e..6145a11c4ae0f 100644
--- a/tests/ui/intrinsics/incorrect-transmute.stderr
+++ b/tests/ui/intrinsics/incorrect-transmute.stderr
@@ -1,18 +1,21 @@
-error[E0658]: the extern "rust-intrinsic" ABI is an implementation detail and perma-unstable
-  --> $DIR/incorrect-transmute.rs:5:8
+error[E0658]: the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items
+  --> $DIR/incorrect-transmute.rs:6:1
    |
-LL | extern "rust-intrinsic" fn transmute() {}
-   |        ^^^^^^^^^^^^^^^^
+LL | #[rustc_intrinsic]
+   | ^^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(intrinsics)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/incorrect-transmute.rs:5:40
+error[E0133]: call to unsafe function `transmute` is unsafe and requires unsafe function or block
+  --> $DIR/incorrect-transmute.rs:2:5
    |
-LL | extern "rust-intrinsic" fn transmute() {}
-   |                                        ^^
+LL |     transmute(); // does not ICE
+   |     ^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0133, E0658.
+For more information about an error, try `rustc --explain E0133`.
diff --git a/tests/ui/intrinsics/intrinsic-atomics.rs b/tests/ui/intrinsics/intrinsic-atomics.rs
index 4ad267e3ddb3f..6bc3f8d884db1 100644
--- a/tests/ui/intrinsics/intrinsic-atomics.rs
+++ b/tests/ui/intrinsics/intrinsic-atomics.rs
@@ -2,33 +2,51 @@
 #![feature(intrinsics)]
 
 mod rusti {
-    extern "rust-intrinsic" {
-        pub fn atomic_cxchg_seqcst_seqcst<T>(dst: *mut T, old: T, src: T) -> (T, bool);
-        pub fn atomic_cxchg_acquire_acquire<T>(dst: *mut T, old: T, src: T) -> (T, bool);
-        pub fn atomic_cxchg_release_relaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
 
-        pub fn atomic_cxchgweak_seqcst_seqcst<T>(dst: *mut T, old: T, src: T) -> (T, bool);
-        pub fn atomic_cxchgweak_acquire_acquire<T>(dst: *mut T, old: T, src: T) -> (T, bool);
-        pub fn atomic_cxchgweak_release_relaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
-
-        pub fn atomic_load_seqcst<T>(src: *const T) -> T;
-        pub fn atomic_load_acquire<T>(src: *const T) -> T;
-
-        pub fn atomic_store_seqcst<T>(dst: *mut T, val: T);
-        pub fn atomic_store_release<T>(dst: *mut T, val: T);
-
-        pub fn atomic_xchg_seqcst<T>(dst: *mut T, src: T) -> T;
-        pub fn atomic_xchg_acquire<T>(dst: *mut T, src: T) -> T;
-        pub fn atomic_xchg_release<T>(dst: *mut T, src: T) -> T;
-
-        pub fn atomic_xadd_seqcst<T>(dst: *mut T, src: T) -> T;
-        pub fn atomic_xadd_acquire<T>(dst: *mut T, src: T) -> T;
-        pub fn atomic_xadd_release<T>(dst: *mut T, src: T) -> T;
-
-        pub fn atomic_xsub_seqcst<T>(dst: *mut T, src: T) -> T;
-        pub fn atomic_xsub_acquire<T>(dst: *mut T, src: T) -> T;
-        pub fn atomic_xsub_release<T>(dst: *mut T, src: T) -> T;
-    }
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_cxchg_seqcst_seqcst<T>(dst: *mut T, old: T, src: T) -> (T, bool);
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_cxchg_acquire_acquire<T>(dst: *mut T, old: T, src: T) -> (T, bool);
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_cxchg_release_relaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
+
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_cxchgweak_seqcst_seqcst<T>(dst: *mut T, old: T, src: T) -> (T, bool);
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_cxchgweak_acquire_acquire<T>(dst: *mut T, old: T, src: T) -> (T, bool);
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_cxchgweak_release_relaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
+
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_load_seqcst<T>(src: *const T) -> T;
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_load_acquire<T>(src: *const T) -> T;
+
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_store_seqcst<T>(dst: *mut T, val: T);
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_store_release<T>(dst: *mut T, val: T);
+
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_xchg_seqcst<T>(dst: *mut T, src: T) -> T;
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_xchg_acquire<T>(dst: *mut T, src: T) -> T;
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_xchg_release<T>(dst: *mut T, src: T) -> T;
+
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_xadd_seqcst<T>(dst: *mut T, src: T) -> T;
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_xadd_acquire<T>(dst: *mut T, src: T) -> T;
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_xadd_release<T>(dst: *mut T, src: T) -> T;
+
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_xsub_seqcst<T>(dst: *mut T, src: T) -> T;
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_xsub_acquire<T>(dst: *mut T, src: T) -> T;
+    #[rustc_intrinsic]
+    pub unsafe fn atomic_xsub_release<T>(dst: *mut T, src: T) -> T;
 }
 
 pub fn main() {
@@ -39,9 +57,9 @@ pub fn main() {
         *x = 5;
         assert_eq!(rusti::atomic_load_acquire(&*x), 5);
 
-        rusti::atomic_store_seqcst(&mut *x,3);
+        rusti::atomic_store_seqcst(&mut *x, 3);
         assert_eq!(*x, 3);
-        rusti::atomic_store_release(&mut *x,1);
+        rusti::atomic_store_release(&mut *x, 1);
         assert_eq!(*x, 1);
 
         assert_eq!(rusti::atomic_cxchg_seqcst_seqcst(&mut *x, 1, 2), (1, true));
diff --git a/tests/ui/intrinsics/invalid-ABI-rust-intrinsic.rs b/tests/ui/intrinsics/invalid-ABI-rust-intrinsic.rs
new file mode 100644
index 0000000000000..4b777deb8b502
--- /dev/null
+++ b/tests/ui/intrinsics/invalid-ABI-rust-intrinsic.rs
@@ -0,0 +1,19 @@
+#![feature(intrinsics)]
+
+trait Foo {
+    extern "rust-intrinsic" fn foo(&self); //~ ERROR invalid ABI
+}
+
+impl Foo for () {
+    extern "rust-intrinsic" fn foo(&self) { //~ ERROR invalid ABI
+    }
+}
+
+extern "rust-intrinsic" fn hello() { //~ ERROR invalid ABI
+}
+
+extern "rust-intrinsic" {
+    //~^ ERROR invalid ABI
+}
+
+fn main() {}
diff --git a/tests/ui/intrinsics/invalid-ABI-rust-intrinsic.stderr b/tests/ui/intrinsics/invalid-ABI-rust-intrinsic.stderr
new file mode 100644
index 0000000000000..fc8bf62915b1b
--- /dev/null
+++ b/tests/ui/intrinsics/invalid-ABI-rust-intrinsic.stderr
@@ -0,0 +1,35 @@
+error[E0703]: invalid ABI: found `rust-intrinsic`
+  --> $DIR/invalid-ABI-rust-intrinsic.rs:4:12
+   |
+LL |     extern "rust-intrinsic" fn foo(&self);
+   |            ^^^^^^^^^^^^^^^^ invalid ABI
+   |
+   = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions
+
+error[E0703]: invalid ABI: found `rust-intrinsic`
+  --> $DIR/invalid-ABI-rust-intrinsic.rs:8:12
+   |
+LL |     extern "rust-intrinsic" fn foo(&self) {
+   |            ^^^^^^^^^^^^^^^^ invalid ABI
+   |
+   = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions
+
+error[E0703]: invalid ABI: found `rust-intrinsic`
+  --> $DIR/invalid-ABI-rust-intrinsic.rs:12:8
+   |
+LL | extern "rust-intrinsic" fn hello() {
+   |        ^^^^^^^^^^^^^^^^ invalid ABI
+   |
+   = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions
+
+error[E0703]: invalid ABI: found `rust-intrinsic`
+  --> $DIR/invalid-ABI-rust-intrinsic.rs:15:8
+   |
+LL | extern "rust-intrinsic" {
+   |        ^^^^^^^^^^^^^^^^ invalid ABI
+   |
+   = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0703`.
diff --git a/tests/ui/intrinsics/issue-28575.rs b/tests/ui/intrinsics/issue-28575.rs
index 141136d25b215..841bc45138a14 100644
--- a/tests/ui/intrinsics/issue-28575.rs
+++ b/tests/ui/intrinsics/issue-28575.rs
@@ -2,6 +2,7 @@
 
 extern "C" {
     pub static FOO: extern "rust-intrinsic" fn();
+    //~^ ERROR invalid ABI
 }
 
 fn main() {
diff --git a/tests/ui/intrinsics/issue-28575.stderr b/tests/ui/intrinsics/issue-28575.stderr
index 8a7816f231f70..09c52aa4c9982 100644
--- a/tests/ui/intrinsics/issue-28575.stderr
+++ b/tests/ui/intrinsics/issue-28575.stderr
@@ -1,11 +1,20 @@
+error[E0703]: invalid ABI: found `rust-intrinsic`
+  --> $DIR/issue-28575.rs:4:28
+   |
+LL |     pub static FOO: extern "rust-intrinsic" fn();
+   |                            ^^^^^^^^^^^^^^^^ invalid ABI
+   |
+   = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions
+
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/issue-28575.rs:8:5
+  --> $DIR/issue-28575.rs:9:5
    |
 LL |     FOO()
    |     ^^^ use of extern static
    |
    = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0133`.
+Some errors have detailed explanations: E0133, E0703.
+For more information about an error, try `rustc --explain E0133`.
diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.rs b/tests/ui/intrinsics/safe-intrinsic-mismatch.rs
index 915a23b59053d..4c301f9dbb09e 100644
--- a/tests/ui/intrinsics/safe-intrinsic-mismatch.rs
+++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.rs
@@ -1,13 +1,14 @@
 #![feature(intrinsics)]
 #![feature(rustc_attrs)]
 
-extern "rust-intrinsic" {
-    fn size_of<T>() -> usize; //~ ERROR intrinsic safety mismatch
-    //~^ ERROR intrinsic safety mismatch
-}
+#[rustc_intrinsic]
+unsafe fn size_of<T>() -> usize;
+//~^ ERROR intrinsic safety mismatch
+//~| ERROR intrinsic has wrong type
 
 #[rustc_intrinsic]
-const fn assume(_b: bool) {} //~ ERROR intrinsic safety mismatch
+const fn assume(_b: bool) {}
+//~^ ERROR intrinsic safety mismatch
 //~| ERROR intrinsic has wrong type
 
 #[rustc_intrinsic]
diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr b/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr
index aa4f294232d2d..04f6daeced2a9 100644
--- a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr
+++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr
@@ -1,16 +1,17 @@
 error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of`
-  --> $DIR/safe-intrinsic-mismatch.rs:5:5
+  --> $DIR/safe-intrinsic-mismatch.rs:5:1
    |
-LL |     fn size_of<T>() -> usize;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | unsafe fn size_of<T>() -> usize;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of`
-  --> $DIR/safe-intrinsic-mismatch.rs:5:5
+error[E0308]: intrinsic has wrong type
+  --> $DIR/safe-intrinsic-mismatch.rs:5:18
    |
-LL |     fn size_of<T>() -> usize;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | unsafe fn size_of<T>() -> usize;
+   |                  ^^^ expected safe fn, found unsafe fn
    |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+   = note: expected signature `fn() -> _`
+              found signature `unsafe fn() -> _`
 
 error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `assume`
   --> $DIR/safe-intrinsic-mismatch.rs:10:1
@@ -28,13 +29,13 @@ LL | const fn assume(_b: bool) {}
               found signature `fn(_)`
 
 error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `const_deallocate`
-  --> $DIR/safe-intrinsic-mismatch.rs:14:1
+  --> $DIR/safe-intrinsic-mismatch.rs:15:1
    |
 LL | const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0308]: intrinsic has wrong type
-  --> $DIR/safe-intrinsic-mismatch.rs:14:26
+  --> $DIR/safe-intrinsic-mismatch.rs:15:26
    |
 LL | const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
    |                          ^ expected unsafe fn, found safe fn
diff --git a/tests/ui/lint/internal_features.rs b/tests/ui/lint/internal_features.rs
index 32ce9540cb364..6456078a5c2fa 100644
--- a/tests/ui/lint/internal_features.rs
+++ b/tests/ui/lint/internal_features.rs
@@ -4,8 +4,7 @@
 //~^ ERROR: internal
 //~| ERROR: internal
 
-extern "rust-intrinsic" {
-    fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
-}
+#[rustc_intrinsic]
+unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
 
 fn main() {}
diff --git a/tests/ui/print-calling-conventions.stdout b/tests/ui/print-calling-conventions.stdout
index 539b2d5dee405..feee8cc3aa9c3 100644
--- a/tests/ui/print-calling-conventions.stdout
+++ b/tests/ui/print-calling-conventions.stdout
@@ -19,7 +19,6 @@ riscv-interrupt-m
 riscv-interrupt-s
 rust-call
 rust-cold
-rust-intrinsic
 stdcall
 stdcall-unwind
 system
diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr
index 7b0fd9799919c..e189012d15c94 100644
--- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr
+++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021-without-dyn.stderr
@@ -26,6 +26,20 @@ help: `A` is dyn-incompatible, use `impl A` to return an opaque type, as long as
 LL |     fn f(a: A) -> impl A;
    |                   ++++
 
+error: associated item referring to unboxed trait object for its own trait
+  --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:4:13
+   |
+LL | trait A: Sized {
+   |       - in this trait
+LL |     fn f(a: A) -> A;
+   |             ^     ^
+   |
+help: you might have meant to use `Self` to refer to the implementing type
+   |
+LL -     fn f(a: A) -> A;
+LL +     fn f(a: Self) -> Self;
+   |
+
 error[E0782]: expected a type, found a trait
   --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:13
    |
@@ -54,6 +68,20 @@ help: `B` is dyn-incompatible, use `impl B` to return an opaque type, as long as
 LL |     fn f(b: B) -> impl B;
    |                   ++++
 
+error: associated item referring to unboxed trait object for its own trait
+  --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:13
+   |
+LL | trait B {
+   |       - in this trait
+LL |     fn f(b: B) -> B;
+   |             ^     ^
+   |
+help: you might have meant to use `Self` to refer to the implementing type
+   |
+LL -     fn f(b: B) -> B;
+LL +     fn f(b: Self) -> Self;
+   |
+
 error[E0782]: expected a type, found a trait
   --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:16:20
    |
@@ -82,34 +110,6 @@ help: `C` is dyn-incompatible, use `impl C` to return an opaque type, as long as
 LL |     fn f(&self, c: C) -> impl C;
    |                          ++++
 
-error: associated item referring to unboxed trait object for its own trait
-  --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:4:13
-   |
-LL | trait A: Sized {
-   |       - in this trait
-LL |     fn f(a: A) -> A;
-   |             ^     ^
-   |
-help: you might have meant to use `Self` to refer to the implementing type
-   |
-LL -     fn f(a: A) -> A;
-LL +     fn f(a: Self) -> Self;
-   |
-
-error: associated item referring to unboxed trait object for its own trait
-  --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:10:13
-   |
-LL | trait B {
-   |       - in this trait
-LL |     fn f(b: B) -> B;
-   |             ^     ^
-   |
-help: you might have meant to use `Self` to refer to the implementing type
-   |
-LL -     fn f(b: B) -> B;
-LL +     fn f(b: Self) -> Self;
-   |
-
 error: associated item referring to unboxed trait object for its own trait
   --> $DIR/dyn-incompatible-trait-should-use-self-2021-without-dyn.rs:16:20
    |
diff --git a/tests/ui/suggestions/issue-116434-2015.stderr b/tests/ui/suggestions/issue-116434-2015.stderr
index e7b8cd2f101d8..07a254432a28d 100644
--- a/tests/ui/suggestions/issue-116434-2015.stderr
+++ b/tests/ui/suggestions/issue-116434-2015.stderr
@@ -12,19 +12,6 @@ help: if this is a dyn-compatible trait, use `dyn`
 LL |     fn foo() -> dyn Clone;
    |                 +++
 
-warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/issue-116434-2015.rs:18:20
-   |
-LL |     fn handle() -> DbHandle;
-   |                    ^^^^^^^^
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: if this is a dyn-compatible trait, use `dyn`
-   |
-LL |     fn handle() -> dyn DbHandle;
-   |                    +++
-
 warning: trait objects without an explicit `dyn` are deprecated
   --> $DIR/issue-116434-2015.rs:3:17
    |
@@ -53,6 +40,19 @@ help: there is an associated type with the same name
 LL |     fn foo() -> Self::Clone;
    |                 ++++++
 
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/issue-116434-2015.rs:18:20
+   |
+LL |     fn handle() -> DbHandle;
+   |                    ^^^^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: if this is a dyn-compatible trait, use `dyn`
+   |
+LL |     fn handle() -> dyn DbHandle;
+   |                    +++
+
 warning: trait objects without an explicit `dyn` are deprecated
   --> $DIR/issue-116434-2015.rs:18:20
    |
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr
index 2a4a5a62ab4c5..7184244f5dc9d 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.stderr
+++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr
@@ -439,6 +439,18 @@ LL |     fn fn_test13(x: _) -> (i32, _) { (x, x) }
    |                           |     not allowed in type signatures
    |                           help: replace with the correct return type: `(i32, i32)`
 
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
+  --> $DIR/typeck_type_placeholder_item.rs:154:21
+   |
+LL | struct BadStruct<_>(_);
+   |                     ^ not allowed in type signatures
+   |
+help: use type parameters instead
+   |
+LL - struct BadStruct<_>(_);
+LL + struct BadStruct<T>(T);
+   |
+
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:140:31
    |
@@ -515,18 +527,6 @@ LL -     fn assoc_fn_test3() -> _;
 LL +     fn assoc_fn_test3<T>() -> T;
    |
 
-error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
-  --> $DIR/typeck_type_placeholder_item.rs:154:21
-   |
-LL | struct BadStruct<_>(_);
-   |                     ^ not allowed in type signatures
-   |
-help: use type parameters instead
-   |
-LL - struct BadStruct<_>(_);
-LL + struct BadStruct<T>(T);
-   |
-
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for implementations
   --> $DIR/typeck_type_placeholder_item.rs:159:15
    |
diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr
index 3b4de0753af0b..59eef0c63278a 100644
--- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr
+++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr
@@ -53,6 +53,12 @@ LL | trait Trait<const N: Trait = bar> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
+error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:12
+   |
+LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+   |            ^^^^^^^^^^^^^^^^^^^^
+
 warning: trait objects without an explicit `dyn` are deprecated
   --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:44
    |
@@ -66,12 +72,6 @@ help: if this is a dyn-compatible trait, use `dyn`
 LL |     fn fnc<const N: Trait = u32>(&self) -> dyn Trait {
    |                                            +++
 
-error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:12
-   |
-LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
-   |            ^^^^^^^^^^^^^^^^^^^^
-
 warning: trait objects without an explicit `dyn` are deprecated
   --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:21
    |

From c8649a31a8eea7c4ed33d68d3fc3b71a2cffd119 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sun, 6 Apr 2025 21:55:06 +0000
Subject: [PATCH 15/17] Stop calling source_span query in significant drop
 order code

---
 .../src/ty/significant_drop_order.rs          |  22 +--
 .../drop/drop-order-comparisons.e2021.stderr  | 176 +++++-------------
 ...nt-if-let-rescope-gated.edition2021.stderr |   8 +-
 .../lint-if-let-rescope-with-macro.stderr     |   8 +-
 tests/ui/drop/lint-if-let-rescope.stderr      |  64 ++-----
 .../ui/drop/lint-tail-expr-drop-order.stderr  |  84 +++------
 ...expr_drop_order-on-coroutine-unwind.stderr |  18 +-
 7 files changed, 100 insertions(+), 280 deletions(-)

diff --git a/compiler/rustc_middle/src/ty/significant_drop_order.rs b/compiler/rustc_middle/src/ty/significant_drop_order.rs
index 4881d611c1282..ce4208f2c445f 100644
--- a/compiler/rustc_middle/src/ty/significant_drop_order.rs
+++ b/compiler/rustc_middle/src/ty/significant_drop_order.rs
@@ -143,25 +143,11 @@ pub fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Span> {
         | ty::UnsafeBinder(_) => None,
 
         ty::Adt(adt_def, _) => {
-            let did = adt_def.did();
-            let try_local_did_span = |did: DefId| {
-                if let Some(local) = did.as_local() {
-                    tcx.source_span(local)
-                } else {
-                    tcx.def_span(did)
-                }
-            };
-            let dtor = if let Some(dtor) = tcx.adt_destructor(did) {
-                dtor.did
-            } else if let Some(dtor) = tcx.adt_async_destructor(did) {
-                return Some(tcx.source_span(dtor.impl_did));
+            if let Some(dtor) = tcx.adt_destructor(adt_def.did()) {
+                Some(tcx.def_span(tcx.parent(dtor.did)))
             } else {
-                return Some(try_local_did_span(did));
-            };
-            let def_key = tcx.def_key(dtor);
-            let Some(parent_index) = def_key.parent else { return Some(try_local_did_span(dtor)) };
-            let parent_did = DefId { index: parent_index, krate: dtor.krate };
-            Some(try_local_did_span(parent_did))
+                Some(tcx.def_span(adt_def.did()))
+            }
         }
         ty::Coroutine(did, _)
         | ty::CoroutineWitness(did, _)
diff --git a/tests/ui/drop/drop-order-comparisons.e2021.stderr b/tests/ui/drop/drop-order-comparisons.e2021.stderr
index 601b0a38412f0..0717a8c1b9b94 100644
--- a/tests/ui/drop/drop-order-comparisons.e2021.stderr
+++ b/tests/ui/drop/drop-order-comparisons.e2021.stderr
@@ -31,39 +31,23 @@ LL | |     }, e.mark(3), e.ok(4));
 note: `#3` invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#1` invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `_v` invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#2` invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 note: the lint level is defined here
   --> $DIR/drop-order-comparisons.rs:28:25
@@ -95,21 +79,13 @@ LL | |     }, e.mark(1), e.ok(4));
 note: `#2` invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#1` invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 warning: relative drop order changing in Rust 2024
@@ -135,21 +111,13 @@ LL | |     }, e.mark(1), e.ok(4));
 note: `#2` invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#1` invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 warning: relative drop order changing in Rust 2024
@@ -175,21 +143,13 @@ LL | |     }, e.mark(2), e.ok(3));
 note: `#2` invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#1` invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 warning: relative drop order changing in Rust 2024
@@ -215,21 +175,13 @@ LL | |     }, e.mark(2), e.ok(3));
 note: `#2` invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#1` invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 warning: `if let` assigns a shorter lifetime since Edition 2024
@@ -245,12 +197,8 @@ LL |     _ = (if let Ok(_) = e.ok(4).as_ref() {
 note: value invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:127:5
    |
@@ -279,12 +227,8 @@ LL |     _ = (if let Ok(_) = e.err(4).as_ref() {} else {
 note: value invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:145:44
    |
@@ -312,12 +256,8 @@ LL |         if let Ok(_) = e.err(4).as_ref() {} else {
 note: value invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:247:43
    |
@@ -345,12 +285,8 @@ LL |         if let true = e.err(9).is_ok() {} else {
 note: value invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:352:41
    |
@@ -378,12 +314,8 @@ LL |         if let Ok(_v) = e.err(8) {} else {
 note: value invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:355:35
    |
@@ -411,12 +343,8 @@ LL |         if let Ok(_) = e.err(7) {} else {
 note: value invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:358:34
    |
@@ -444,12 +372,8 @@ LL |         if let Ok(_) = e.err(6).as_ref() {} else {
 note: value invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:361:43
    |
@@ -477,12 +401,8 @@ LL |         if let Ok(_v) = e.err(5) {} else {
 note: value invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:365:35
    |
@@ -510,12 +430,8 @@ LL |         if let Ok(_) = e.err(4) {} else {
 note: value invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:368:34
    |
@@ -543,12 +459,8 @@ LL |         if let Ok(_) = e.err(4).as_ref() {} else {
 note: value invokes this custom destructor
   --> $DIR/drop-order-comparisons.rs:571:1
    |
-LL | / impl<'b> Drop for LogDrop<'b> {
-LL | |     fn drop(&mut self) {
-LL | |         self.0.mark(self.1);
-LL | |     }
-LL | | }
-   | |_^
+LL | impl<'b> Drop for LogDrop<'b> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:404:43
    |
diff --git a/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr b/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr
index 070ba1c6a4cfa..0d6974d516b6e 100644
--- a/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr
+++ b/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr
@@ -11,12 +11,8 @@ LL |     if let Some(_value) = Droppy.get() {
 note: value invokes this custom destructor
   --> $DIR/lint-if-let-rescope-gated.rs:14:1
    |
-LL | / impl Drop for Droppy {
-LL | |     fn drop(&mut self) {
-LL | |         println!("dropped");
-LL | |     }
-LL | | }
-   | |_^
+LL | impl Drop for Droppy {
+   | ^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope-gated.rs:30:5
    |
diff --git a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr
index f1ca0ba57de4f..a0afb8eddb532 100644
--- a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr
+++ b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr
@@ -18,12 +18,8 @@ LL | |     };
 note: value invokes this custom destructor
   --> $DIR/lint-if-let-rescope-with-macro.rs:22:1
    |
-LL | / impl Drop for Droppy {
-LL | |     fn drop(&mut self) {
-LL | |         println!("dropped");
-LL | |     }
-LL | | }
-   | |_^
+LL | impl Drop for Droppy {
+   | ^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope-with-macro.rs:12:38
    |
diff --git a/tests/ui/drop/lint-if-let-rescope.stderr b/tests/ui/drop/lint-if-let-rescope.stderr
index e95ec8fcea7fe..ca2416efcb1a2 100644
--- a/tests/ui/drop/lint-if-let-rescope.stderr
+++ b/tests/ui/drop/lint-if-let-rescope.stderr
@@ -11,12 +11,8 @@ LL |     if let Some(_value) = droppy().get() {
 note: value invokes this custom destructor
   --> $DIR/lint-if-let-rescope.rs:11:1
    |
-LL | / impl Drop for Droppy {
-LL | |     fn drop(&mut self) {
-LL | |         println!("dropped");
-LL | |     }
-LL | | }
-   | |_^
+LL | impl Drop for Droppy {
+   | ^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope.rs:32:5
    |
@@ -55,21 +51,13 @@ LL |     } else if let Some(_value) = droppy().get() {
 note: value invokes this custom destructor
   --> $DIR/lint-if-let-rescope.rs:11:1
    |
-LL | / impl Drop for Droppy {
-LL | |     fn drop(&mut self) {
-LL | |         println!("dropped");
-LL | |     }
-LL | | }
-   | |_^
+LL | impl Drop for Droppy {
+   | ^^^^^^^^^^^^^^^^^^^^
 note: value invokes this custom destructor
   --> $DIR/lint-if-let-rescope.rs:11:1
    |
-LL | / impl Drop for Droppy {
-LL | |     fn drop(&mut self) {
-LL | |         println!("dropped");
-LL | |     }
-LL | | }
-   | |_^
+LL | impl Drop for Droppy {
+   | ^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope.rs:42:5
    |
@@ -105,12 +93,8 @@ LL |     } else if let Some(_value) = droppy().get() {
 note: value invokes this custom destructor
   --> $DIR/lint-if-let-rescope.rs:11:1
    |
-LL | / impl Drop for Droppy {
-LL | |     fn drop(&mut self) {
-LL | |         println!("dropped");
-LL | |     }
-LL | | }
-   | |_^
+LL | impl Drop for Droppy {
+   | ^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope.rs:54:5
    |
@@ -140,12 +124,8 @@ LL |     if let Some(1) = { if let Some(_value) = Droppy.get() { Some(1) } else
 note: value invokes this custom destructor
   --> $DIR/lint-if-let-rescope.rs:11:1
    |
-LL | / impl Drop for Droppy {
-LL | |     fn drop(&mut self) {
-LL | |         println!("dropped");
-LL | |     }
-LL | | }
-   | |_^
+LL | impl Drop for Droppy {
+   | ^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope.rs:58:69
    |
@@ -170,12 +150,8 @@ LL |     if (if let Some(_value) = droppy().get() { true } else { false }) {
 note: value invokes this custom destructor
   --> $DIR/lint-if-let-rescope.rs:11:1
    |
-LL | / impl Drop for Droppy {
-LL | |     fn drop(&mut self) {
-LL | |         println!("dropped");
-LL | |     }
-LL | | }
-   | |_^
+LL | impl Drop for Droppy {
+   | ^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope.rs:72:53
    |
@@ -200,12 +176,8 @@ LL |     } else if (((if let Some(_value) = droppy().get() { true } else { false
 note: value invokes this custom destructor
   --> $DIR/lint-if-let-rescope.rs:11:1
    |
-LL | / impl Drop for Droppy {
-LL | |     fn drop(&mut self) {
-LL | |         println!("dropped");
-LL | |     }
-LL | | }
-   | |_^
+LL | impl Drop for Droppy {
+   | ^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope.rs:78:62
    |
@@ -230,12 +202,8 @@ LL |     while (if let Some(_value) = droppy().get() { false } else { true }) {
 note: value invokes this custom destructor
   --> $DIR/lint-if-let-rescope.rs:11:1
    |
-LL | / impl Drop for Droppy {
-LL | |     fn drop(&mut self) {
-LL | |         println!("dropped");
-LL | |     }
-LL | | }
-   | |_^
+LL | impl Drop for Droppy {
+   | ^^^^^^^^^^^^^^^^^^^^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope.rs:90:57
    |
diff --git a/tests/ui/drop/lint-tail-expr-drop-order.stderr b/tests/ui/drop/lint-tail-expr-drop-order.stderr
index 6ff9b7c12681d..e124e9874d0b4 100644
--- a/tests/ui/drop/lint-tail-expr-drop-order.stderr
+++ b/tests/ui/drop/lint-tail-expr-drop-order.stderr
@@ -21,17 +21,13 @@ LL | }
 note: `#1` invokes this custom destructor
   --> $DIR/lint-tail-expr-drop-order.rs:10:1
    |
-LL | / impl Drop for LoudDropper {
-...  |
-LL | | }
-   | |_^
+LL | impl Drop for LoudDropper {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `x` invokes this custom destructor
   --> $DIR/lint-tail-expr-drop-order.rs:10:1
    |
-LL | / impl Drop for LoudDropper {
-...  |
-LL | | }
-   | |_^
+LL | impl Drop for LoudDropper {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 note: the lint level is defined here
   --> $DIR/lint-tail-expr-drop-order.rs:6:9
@@ -62,17 +58,13 @@ LL |     }
 note: `#1` invokes this custom destructor
   --> $DIR/lint-tail-expr-drop-order.rs:10:1
    |
-LL | / impl Drop for LoudDropper {
-...  |
-LL | | }
-   | |_^
+LL | impl Drop for LoudDropper {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `x` invokes this custom destructor
   --> $DIR/lint-tail-expr-drop-order.rs:10:1
    |
-LL | / impl Drop for LoudDropper {
-...  |
-LL | | }
-   | |_^
+LL | impl Drop for LoudDropper {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 error: relative drop order changing in Rust 2024
@@ -98,17 +90,13 @@ LL | }
 note: `#1` invokes this custom destructor
   --> $DIR/lint-tail-expr-drop-order.rs:10:1
    |
-LL | / impl Drop for LoudDropper {
-...  |
-LL | | }
-   | |_^
+LL | impl Drop for LoudDropper {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `x` invokes this custom destructor
   --> $DIR/lint-tail-expr-drop-order.rs:10:1
    |
-LL | / impl Drop for LoudDropper {
-...  |
-LL | | }
-   | |_^
+LL | impl Drop for LoudDropper {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 error: relative drop order changing in Rust 2024
@@ -134,10 +122,8 @@ LL | }
 note: `#1` invokes this custom destructor
   --> $DIR/lint-tail-expr-drop-order.rs:10:1
    |
-LL | / impl Drop for LoudDropper {
-...  |
-LL | | }
-   | |_^
+LL | impl Drop for LoudDropper {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 error: relative drop order changing in Rust 2024
@@ -185,17 +171,13 @@ LL | }
 note: `#1` invokes this custom destructor
   --> $DIR/lint-tail-expr-drop-order.rs:10:1
    |
-LL | / impl Drop for LoudDropper {
-...  |
-LL | | }
-   | |_^
+LL | impl Drop for LoudDropper {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `x` invokes this custom destructor
   --> $DIR/lint-tail-expr-drop-order.rs:10:1
    |
-LL | / impl Drop for LoudDropper {
-...  |
-LL | | }
-   | |_^
+LL | impl Drop for LoudDropper {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 error: relative drop order changing in Rust 2024
@@ -221,23 +203,13 @@ LL | }
 note: `#1` invokes this custom destructor
   --> $DIR/lint-tail-expr-drop-order.rs:193:5
    |
-LL | /     impl Drop for LoudDropper3 {
-LL | |
-LL | |         fn drop(&mut self) {
-LL | |             println!("loud drop");
-LL | |         }
-LL | |     }
-   | |_____^
+LL |     impl Drop for LoudDropper3 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `x` invokes this custom destructor
   --> $DIR/lint-tail-expr-drop-order.rs:205:5
    |
-LL | /     impl Drop for LoudDropper2 {
-LL | |
-LL | |         fn drop(&mut self) {
-LL | |             println!("loud drop");
-LL | |         }
-LL | |     }
-   | |_____^
+LL |     impl Drop for LoudDropper2 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 error: relative drop order changing in Rust 2024
@@ -263,17 +235,13 @@ LL |     ));
 note: `#1` invokes this custom destructor
   --> $DIR/lint-tail-expr-drop-order.rs:10:1
    |
-LL | / impl Drop for LoudDropper {
-...  |
-LL | | }
-   | |_^
+LL | impl Drop for LoudDropper {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `_x` invokes this custom destructor
   --> $DIR/lint-tail-expr-drop-order.rs:10:1
    |
-LL | / impl Drop for LoudDropper {
-...  |
-LL | | }
-   | |_^
+LL | impl Drop for LoudDropper {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 
 error: aborting due to 8 previous errors
diff --git a/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr
index b0f971dd5cec6..7bf452e2496cb 100644
--- a/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr
+++ b/tests/ui/drop/tail_expr_drop_order-on-coroutine-unwind.stderr
@@ -27,24 +27,18 @@ LL |     }
 note: `#2` invokes this custom destructor
   --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:9:1
    |
-LL | / impl std::ops::Drop for Drop {
-LL | |     fn drop(&mut self) {}
-LL | | }
-   | |_^
+LL | impl std::ops::Drop for Drop {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `#1` invokes this custom destructor
   --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:9:1
    |
-LL | / impl std::ops::Drop for Drop {
-LL | |     fn drop(&mut self) {}
-LL | | }
-   | |_^
+LL | impl std::ops::Drop for Drop {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: `e` invokes this custom destructor
   --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:9:1
    |
-LL | / impl std::ops::Drop for Drop {
-LL | |     fn drop(&mut self) {}
-LL | | }
-   | |_^
+LL | impl std::ops::Drop for Drop {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages
 note: the lint level is defined here
   --> $DIR/tail_expr_drop_order-on-coroutine-unwind.rs:6:9

From d111aa87f1588d2ac0c282baa1b7d70e87231d52 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Mon, 7 Apr 2025 05:03:35 +0000
Subject: [PATCH 16/17] Trivial tweaks to stop tracking source span directly

---
 .../rustc_borrowck/src/region_infer/mod.rs    | 32 +++++++++++--------
 compiler/rustc_hir_typeck/src/closure.rs      |  2 +-
 compiler/rustc_hir_typeck/src/lib.rs          |  2 +-
 3 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index a80d74d9e370a..5756a5e7c7c5e 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -22,7 +22,7 @@ use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex,
 use rustc_mir_dataflow::points::DenseLocationMap;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::{DUMMY_SP, Span};
-use tracing::{debug, instrument, trace};
+use tracing::{Level, debug, enabled, instrument, trace};
 
 use crate::BorrowckInferCtxt;
 use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph};
@@ -327,11 +327,13 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
     let mut var_to_origin_sorted = var_to_origin.clone().into_iter().collect::<Vec<_>>();
     var_to_origin_sorted.sort_by_key(|vto| vto.0);
 
-    let mut reg_vars_to_origins_str = "region variables to origins:\n".to_string();
-    for (reg_var, origin) in var_to_origin_sorted.into_iter() {
-        reg_vars_to_origins_str.push_str(&format!("{reg_var:?}: {origin:?}\n"));
+    if enabled!(Level::DEBUG) {
+        let mut reg_vars_to_origins_str = "region variables to origins:\n".to_string();
+        for (reg_var, origin) in var_to_origin_sorted.into_iter() {
+            reg_vars_to_origins_str.push_str(&format!("{reg_var:?}: {origin:?}\n"));
+        }
+        debug!("{}", reg_vars_to_origins_str);
     }
-    debug!("{}", reg_vars_to_origins_str);
 
     let num_components = sccs.num_sccs();
     let mut components = vec![FxIndexSet::default(); num_components];
@@ -342,16 +344,18 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
         components[scc_idx.as_usize()].insert((reg_var, *origin));
     }
 
-    let mut components_str = "strongly connected components:".to_string();
-    for (scc_idx, reg_vars_origins) in components.iter().enumerate() {
-        let regions_info = reg_vars_origins.clone().into_iter().collect::<Vec<_>>();
-        components_str.push_str(&format!(
-            "{:?}: {:?},\n)",
-            ConstraintSccIndex::from_usize(scc_idx),
-            regions_info,
-        ))
+    if enabled!(Level::DEBUG) {
+        let mut components_str = "strongly connected components:".to_string();
+        for (scc_idx, reg_vars_origins) in components.iter().enumerate() {
+            let regions_info = reg_vars_origins.clone().into_iter().collect::<Vec<_>>();
+            components_str.push_str(&format!(
+                "{:?}: {:?},\n)",
+                ConstraintSccIndex::from_usize(scc_idx),
+                regions_info,
+            ))
+        }
+        debug!("{}", components_str);
     }
-    debug!("{}", components_str);
 
     // calculate the best representative for each component
     let components_representatives = components
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 467ca26e7eab1..b8968b58769a2 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -970,7 +970,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result);
 
         // Normalize only after registering in `user_provided_sigs`.
-        self.normalize(self.tcx.hir_span(hir_id), result)
+        self.normalize(self.tcx.def_span(expr_def_id), result)
     }
 
     /// Invoked when we are translating the coroutine that results
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 46389668de7c3..1d86ff14471a5 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -117,7 +117,7 @@ fn typeck_with_inspect<'tcx>(
 
     let id = tcx.local_def_id_to_hir_id(def_id);
     let node = tcx.hir_node(id);
-    let span = tcx.hir_span(id);
+    let span = tcx.def_span(def_id);
 
     // Figure out what primary body this item has.
     let body_id = node.body_id().unwrap_or_else(|| {

From 4322b6e97d6ad438c6c9ef1ea92e8ba00c056d9c Mon Sep 17 00:00:00 2001
From: Zalathar <Zalathar@users.noreply.github.com>
Date: Mon, 31 Mar 2025 12:51:16 +1100
Subject: [PATCH 17/17] coverage: Build the CGU's global file table as late as
 possible

---
 .../src/coverageinfo/mapgen.rs                | 152 ++++++++++--------
 .../src/coverageinfo/mapgen/covfun.rs         |  42 +++--
 .../src/coverageinfo/mapgen/unused.rs         |   4 +-
 3 files changed, 110 insertions(+), 88 deletions(-)

diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 5e62ce285dd8c..55b1e728b70db 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -53,13 +53,6 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
         None => return,
     };
 
-    // The order of entries in this global file table needs to be deterministic,
-    // and ideally should also be independent of the details of stable-hashing,
-    // because coverage tests snapshots (`.cov-map`) can observe the order and
-    // would need to be re-blessed if it changes. As long as those requirements
-    // are satisfied, the order can be arbitrary.
-    let mut global_file_table = GlobalFileTable::new();
-
     let mut covfun_records = instances_used
         .iter()
         .copied()
@@ -67,17 +60,13 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
         // order that doesn't depend on the stable-hash-based order in which
         // instances were visited during codegen.
         .sorted_by_cached_key(|&instance| tcx.symbol_name(instance).name)
-        .filter_map(|instance| prepare_covfun_record(tcx, &mut global_file_table, instance, true))
+        .filter_map(|instance| prepare_covfun_record(tcx, instance, true))
         .collect::<Vec<_>>();
 
     // In a single designated CGU, also prepare covfun records for functions
     // in this crate that were instrumented for coverage, but are unused.
     if cx.codegen_unit.is_code_coverage_dead_code_cgu() {
-        unused::prepare_covfun_records_for_unused_functions(
-            cx,
-            &mut global_file_table,
-            &mut covfun_records,
-        );
+        unused::prepare_covfun_records_for_unused_functions(cx, &mut covfun_records);
     }
 
     // If there are no covfun records for this CGU, don't generate a covmap record.
@@ -89,68 +78,88 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
         return;
     }
 
-    // Encode all filenames referenced by coverage mappings in this CGU.
-    let filenames_buffer = global_file_table.make_filenames_buffer(tcx);
-    // The `llvm-cov` tool uses this hash to associate each covfun record with
-    // its corresponding filenames table, since the final binary will typically
-    // contain multiple covmap records from different compilation units.
-    let filenames_hash = llvm_cov::hash_bytes(&filenames_buffer);
+    // Prepare the global file table for this CGU, containing all paths needed
+    // by one or more covfun records.
+    let global_file_table =
+        GlobalFileTable::build(tcx, covfun_records.iter().flat_map(|c| c.all_source_files()));
 
     for covfun in &covfun_records {
-        covfun::generate_covfun_record(cx, filenames_hash, covfun)
+        covfun::generate_covfun_record(cx, &global_file_table, covfun)
     }
 
     // Generate the coverage map header, which contains the filenames used by
     // this CGU's coverage mappings, and store it in a well-known global.
     // (This is skipped if we returned early due to having no covfun records.)
-    generate_covmap_record(cx, covmap_version, &filenames_buffer);
+    generate_covmap_record(cx, covmap_version, &global_file_table.filenames_buffer);
 }
 
-/// Maps "global" (per-CGU) file ID numbers to their underlying source files.
+/// Maps "global" (per-CGU) file ID numbers to their underlying source file paths.
+#[derive(Debug)]
 struct GlobalFileTable {
     /// This "raw" table doesn't include the working dir, so a file's
     /// global ID is its index in this set **plus one**.
-    raw_file_table: FxIndexMap<StableSourceFileId, Arc<SourceFile>>,
+    raw_file_table: FxIndexMap<StableSourceFileId, String>,
+
+    /// The file table in encoded form (possibly compressed), which can be
+    /// included directly in this CGU's `__llvm_covmap` record.
+    filenames_buffer: Vec<u8>,
+
+    /// Truncated hash of the bytes in `filenames_buffer`.
+    ///
+    /// The `llvm-cov` tool uses this hash to associate each covfun record with
+    /// its corresponding filenames table, since the final binary will typically
+    /// contain multiple covmap records from different compilation units.
+    filenames_hash: u64,
 }
 
 impl GlobalFileTable {
-    fn new() -> Self {
-        Self { raw_file_table: FxIndexMap::default() }
-    }
+    /// Builds a "global file table" for this CGU, mapping numeric IDs to
+    /// path strings.
+    fn build<'a>(tcx: TyCtxt<'_>, all_files: impl Iterator<Item = &'a SourceFile>) -> Self {
+        let mut raw_file_table = FxIndexMap::default();
+
+        for file in all_files {
+            raw_file_table.entry(file.stable_id).or_insert_with(|| {
+                file.name
+                    .for_scope(tcx.sess, RemapPathScopeComponents::MACRO)
+                    .to_string_lossy()
+                    .into_owned()
+            });
+        }
+
+        // FIXME(Zalathar): Consider sorting the file table here, but maybe
+        // only after adding filename support to coverage-dump, so that the
+        // table order isn't directly visible in `.coverage-map` snapshots.
+
+        let mut table = Vec::with_capacity(raw_file_table.len() + 1);
+
+        // Since version 6 of the LLVM coverage mapping format, the first entry
+        // in the global file table is treated as a base directory, used to
+        // resolve any other entries that are stored as relative paths.
+        let base_dir = tcx
+            .sess
+            .opts
+            .working_dir
+            .for_scope(tcx.sess, RemapPathScopeComponents::MACRO)
+            .to_string_lossy();
+        table.push(base_dir.as_ref());
 
-    fn global_file_id_for_file(&mut self, file: &Arc<SourceFile>) -> GlobalFileId {
-        // Ensure the given file has a table entry, and get its index.
-        let entry = self.raw_file_table.entry(file.stable_id);
-        let raw_id = entry.index();
-        entry.or_insert_with(|| Arc::clone(file));
-
-        // The raw file table doesn't include an entry for the working dir
-        // (which has ID 0), so add 1 to get the correct ID.
-        GlobalFileId::from_usize(raw_id + 1)
-    }
+        // Add the regular entries after the base directory.
+        table.extend(raw_file_table.values().map(|name| name.as_str()));
 
-    fn make_filenames_buffer(&self, tcx: TyCtxt<'_>) -> Vec<u8> {
-        let mut table = Vec::with_capacity(self.raw_file_table.len() + 1);
-
-        // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
-        // requires setting the first filename to the compilation directory.
-        // Since rustc generates coverage maps with relative paths, the
-        // compilation directory can be combined with the relative paths
-        // to get absolute paths, if needed.
-        table.push(
-            tcx.sess
-                .opts
-                .working_dir
-                .for_scope(tcx.sess, RemapPathScopeComponents::MACRO)
-                .to_string_lossy(),
-        );
+        // Encode the file table into a buffer, and get the hash of its encoded
+        // bytes, so that we can embed that hash in `__llvm_covfun` records.
+        let filenames_buffer = llvm_cov::write_filenames_to_buffer(&table);
+        let filenames_hash = llvm_cov::hash_bytes(&filenames_buffer);
 
-        // Add the regular entries after the base directory.
-        table.extend(self.raw_file_table.values().map(|file| {
-            file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy()
-        }));
+        Self { raw_file_table, filenames_buffer, filenames_hash }
+    }
 
-        llvm_cov::write_filenames_to_buffer(&table)
+    fn get_existing_id(&self, file: &SourceFile) -> Option<GlobalFileId> {
+        let raw_id = self.raw_file_table.get_index_of(&file.stable_id)?;
+        // The raw file table doesn't include an entry for the base dir
+        // (which has ID 0), so add 1 to get the correct ID.
+        Some(GlobalFileId::from_usize(raw_id + 1))
     }
 }
 
@@ -166,26 +175,31 @@ rustc_index::newtype_index! {
     struct LocalFileId {}
 }
 
-/// Holds a mapping from "local" (per-function) file IDs to "global" (per-CGU)
-/// file IDs.
+/// Holds a mapping from "local" (per-function) file IDs to their corresponding
+/// source files.
 #[derive(Debug, Default)]
 struct VirtualFileMapping {
-    local_to_global: IndexVec<LocalFileId, GlobalFileId>,
-    global_to_local: FxIndexMap<GlobalFileId, LocalFileId>,
+    local_file_table: IndexVec<LocalFileId, Arc<SourceFile>>,
 }
 
 impl VirtualFileMapping {
-    fn local_id_for_global(&mut self, global_file_id: GlobalFileId) -> LocalFileId {
-        *self
-            .global_to_local
-            .entry(global_file_id)
-            .or_insert_with(|| self.local_to_global.push(global_file_id))
+    fn push_file(&mut self, source_file: &Arc<SourceFile>) -> LocalFileId {
+        self.local_file_table.push(Arc::clone(source_file))
     }
 
-    fn to_vec(&self) -> Vec<u32> {
-        // This clone could be avoided by transmuting `&[GlobalFileId]` to `&[u32]`,
-        // but it isn't hot or expensive enough to justify the extra unsafety.
-        self.local_to_global.iter().map(|&global| GlobalFileId::as_u32(global)).collect()
+    /// Resolves all of the filenames in this local file mapping to a list of
+    /// global file IDs in its CGU, for inclusion in this function's
+    /// `__llvm_covfun` record.
+    ///
+    /// The global file IDs are returned as `u32` to make FFI easier.
+    fn resolve_all(&self, global_file_table: &GlobalFileTable) -> Option<Vec<u32>> {
+        self.local_file_table
+            .iter()
+            .map(|file| try {
+                let id = global_file_table.get_existing_id(file)?;
+                GlobalFileId::as_u32(id)
+            })
+            .collect::<Option<Vec<_>>>()
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
index 93419c2caad25..7bdbc68595290 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs
@@ -5,6 +5,7 @@
 //! [^win]: On Windows the section name is `.lcovfun`.
 
 use std::ffi::CString;
+use std::sync::Arc;
 
 use rustc_abi::Align;
 use rustc_codegen_ssa::traits::{
@@ -15,7 +16,7 @@ use rustc_middle::mir::coverage::{
     MappingKind, Op,
 };
 use rustc_middle::ty::{Instance, TyCtxt};
-use rustc_span::Span;
+use rustc_span::{SourceFile, Span};
 use rustc_target::spec::HasTargetSpec;
 use tracing::debug;
 
@@ -37,9 +38,16 @@ pub(crate) struct CovfunRecord<'tcx> {
     regions: ffi::Regions,
 }
 
+impl<'tcx> CovfunRecord<'tcx> {
+    /// Iterator that yields all source files referred to by this function's
+    /// coverage mappings. Used to build the global file table for the CGU.
+    pub(crate) fn all_source_files(&self) -> impl Iterator<Item = &SourceFile> {
+        self.virtual_file_mapping.local_file_table.iter().map(Arc::as_ref)
+    }
+}
+
 pub(crate) fn prepare_covfun_record<'tcx>(
     tcx: TyCtxt<'tcx>,
-    global_file_table: &mut GlobalFileTable,
     instance: Instance<'tcx>,
     is_used: bool,
 ) -> Option<CovfunRecord<'tcx>> {
@@ -57,7 +65,7 @@ pub(crate) fn prepare_covfun_record<'tcx>(
         regions: ffi::Regions::default(),
     };
 
-    fill_region_tables(tcx, global_file_table, fn_cov_info, ids_info, &mut covfun);
+    fill_region_tables(tcx, fn_cov_info, ids_info, &mut covfun);
 
     if covfun.regions.has_no_regions() {
         debug!(?covfun, "function has no mappings to embed; skipping");
@@ -92,7 +100,6 @@ fn prepare_expressions(ids_info: &CoverageIdsInfo) -> Vec<ffi::CounterExpression
 /// Populates the mapping region tables in the current function's covfun record.
 fn fill_region_tables<'tcx>(
     tcx: TyCtxt<'tcx>,
-    global_file_table: &mut GlobalFileTable,
     fn_cov_info: &'tcx FunctionCoverageInfo,
     ids_info: &'tcx CoverageIdsInfo,
     covfun: &mut CovfunRecord<'tcx>,
@@ -106,11 +113,7 @@ fn fill_region_tables<'tcx>(
     };
     let source_file = source_map.lookup_source_file(first_span.lo());
 
-    // Look up the global file ID for that file.
-    let global_file_id = global_file_table.global_file_id_for_file(&source_file);
-
-    // Associate that global file ID with a local file ID for this function.
-    let local_file_id = covfun.virtual_file_mapping.local_id_for_global(global_file_id);
+    let local_file_id = covfun.virtual_file_mapping.push_file(&source_file);
 
     // In rare cases, _all_ of a function's spans are discarded, and coverage
     // codegen needs to handle that gracefully to avoid #133606.
@@ -179,7 +182,7 @@ fn fill_region_tables<'tcx>(
 /// as a global variable in the `__llvm_covfun` section.
 pub(crate) fn generate_covfun_record<'tcx>(
     cx: &CodegenCx<'_, 'tcx>,
-    filenames_hash: u64,
+    global_file_table: &GlobalFileTable,
     covfun: &CovfunRecord<'tcx>,
 ) {
     let &CovfunRecord {
@@ -191,12 +194,19 @@ pub(crate) fn generate_covfun_record<'tcx>(
         ref regions,
     } = covfun;
 
+    let Some(local_file_table) = virtual_file_mapping.resolve_all(global_file_table) else {
+        debug_assert!(
+            false,
+            "all local files should be present in the global file table: \
+                global_file_table = {global_file_table:?}, \
+                virtual_file_mapping = {virtual_file_mapping:?}"
+        );
+        return;
+    };
+
     // Encode the function's coverage mappings into a buffer.
-    let coverage_mapping_buffer = llvm_cov::write_function_mappings_to_buffer(
-        &virtual_file_mapping.to_vec(),
-        expressions,
-        regions,
-    );
+    let coverage_mapping_buffer =
+        llvm_cov::write_function_mappings_to_buffer(&local_file_table, expressions, regions);
 
     // A covfun record consists of four target-endian integers, followed by the
     // encoded mapping data in bytes. Note that the length field is 32 bits.
@@ -209,7 +219,7 @@ pub(crate) fn generate_covfun_record<'tcx>(
             cx.const_u64(func_name_hash),
             cx.const_u32(coverage_mapping_buffer.len() as u32),
             cx.const_u64(source_hash),
-            cx.const_u64(filenames_hash),
+            cx.const_u64(global_file_table.filenames_hash),
             cx.const_bytes(&coverage_mapping_buffer),
         ],
         // This struct needs to be packed, so that the 32-bit length field
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs
index ab030f5b6152a..68f60f169b5b5 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs
@@ -7,7 +7,6 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::def_id::DefIdSet;
 
 use crate::common::CodegenCx;
-use crate::coverageinfo::mapgen::GlobalFileTable;
 use crate::coverageinfo::mapgen::covfun::{CovfunRecord, prepare_covfun_record};
 use crate::llvm;
 
@@ -21,7 +20,6 @@ use crate::llvm;
 /// its embedded coverage data.
 pub(crate) fn prepare_covfun_records_for_unused_functions<'tcx>(
     cx: &CodegenCx<'_, 'tcx>,
-    global_file_table: &mut GlobalFileTable,
     covfun_records: &mut Vec<CovfunRecord<'tcx>>,
 ) {
     assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu());
@@ -33,7 +31,7 @@ pub(crate) fn prepare_covfun_records_for_unused_functions<'tcx>(
     // Try to create a covfun record for each unused function.
     let mut name_globals = Vec::with_capacity(unused_instances.len());
     covfun_records.extend(unused_instances.into_iter().filter_map(|unused| try {
-        let record = prepare_covfun_record(cx.tcx, global_file_table, unused.instance, false)?;
+        let record = prepare_covfun_record(cx.tcx, unused.instance, false)?;
         // If successful, also store its symbol name in a global constant.
         name_globals.push(cx.const_str(unused.symbol_name.name).0);
         record